17

Javaがどのメソッドを実行するかを選択する方法を理解しようとしています:

//Example 1 prints Square:add(Figure)
Figure fs = new Square();
fs.add(fs);

//Example 2 prints Square:add(Figure)
Rectangle rs = new Square();
rs.add(fs);

//Example 3 prints Rectangle:add(Rectangle). Expected Square:add(Square)
rs.add(new Square());

//Example 4 prints Rectangle:add(Rectangle). Expected Square:add(Figure)
Square ss = new Square();
ss.add(rs);

class Figure
{
    public void add(Figure f){ System.out.println("Figure:add(Figure)"); }
}

class Rectangle extends Figure
{
    @Override
    public void add(Figure f){ System.out.println("Rectangle:add(Figure)"); }
    public void add(Rectangle r){ System.out.println("Rectangle:add(Rectangle)"); }
}

class Square extends Rectangle
{
    @Override
    public void add(Figure f){ System.out.println("Square:add(Figure)"); }
    public void add(Square s){ System.out.println("Square:add(Square)"); }
}

ここで学んだことは

  • メソッドのシグネチャは、コンパイル時のデータ型に基づいて決定されます
  • 実際に呼び出されるメソッドは、メソッドが呼び出されるオブジェクトの動的タイプによって異なります。

それに基づいて、最初の 2 つの呼び出しの結果は期待どおりです。ただし、例 3 と 4 の結果がわかりません。

Java言語仕様で規定されているようですが、よくわかりません。

4

2 に答える 2

20

しかし、例3と4の結果がわかりません。

さて、それらを個別に見てみましょう。

例3

//Example 3 prints Rectangle:add(Rectangle). Expected Square:add(Square)
rs.add(new Square());

重要な部分は、式とのコンパイル時の型です。rsnew Square()

rsはとしてのみ宣言されてRectangleいるため、コンパイラはによって宣言されたメソッドRectangleとそのスーパークラスを調べます。

public void add(Figure f)
public void add(Rectangle r)

式のタイプnew Square()Squareであるため、両方の方法を適用できますが、2番目の方法はより具体的です。

したがって、コンパイラはを参照するadd(Rectangle)オブジェクトを呼び出しますrs。コンパイル時の面は以上です。

実行時に、の値は-rsのインスタンスを参照しますが、オーバーライドしないため、選択されたメソッドは次の実装です。SquareSquareadd(Rectangle)Rectangle

public void add(Rectangle r){ System.out.println("Rectangle:add(Rectangle)"); }

例4

//Example 4 prints Rectangle:add(Rectangle). Expected Square:add(Figure)
Square ss = new Square();
ss.add(rs);

繰り返しになりますが、関連するコンパイル時の型について考えてみましょう...ssは型Squareでありrs、型ですRectangle(コンパイル時の型、覚えておいてください)。

によって宣言されたメソッドSquareとそのスーパークラスは次のとおりです。

public void add(Figure f)
public void add(Rectangle r)
public void add(Square s)

のコンパイル時タイプrsはのみRectangle(ではないSquare)であるため、最初の2つの方法は適用可能ですが、3番目の方法は適用できません。したがって、ここでも、add(Rectangle)コンパイル時に選択されます(より具体的であるためadd(Figure))。

繰り返しますが、の実行時間タイプはでssありSquare、これはオーバーライドしないadd(Rectangle)ため、の実装Rectangleが使用されます。

ここに混乱しているものがあれば教えてください-どの部分について具体的に説明できれば、それは素晴らしいことです。

于 2013-02-03T19:37:52.543 に答える
4
rs.add(new Square());

rs の宣言型は Rectangle です。したがって、Rectangle のメソッドと、Square または Square と互換性のある型を引数として取るすべてのスーパークラスを調べます。add(Rectangle)Square は Rectangle であり、Rectangle は Figure よりも具体的であるため、最も具体的なものです。

Square ss = new Square();
ss.add(rs);

add(Rectangle)Square とすべてのスーパークラスでメソッドを探します。Rectangle.add(Rectangle)適用されSquare.add(Square)ないため (Rectangle は Square ではありません)、Square.add(Figure)あまり具体的ではありません。

于 2013-02-03T19:40:14.667 に答える