我试图了解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)"); }
}
我所学到的here是
基于此,前两次调用的结果与预期一致。但是,我不理解示例3和4的结果。
似乎在java language specification中指定,但我不明白。
答案 0 :(得分:19)
但是,我不理解示例3和4的结果。
好的,让我们分别看一下。
示例3
//Example 3 prints Rectangle:add(Rectangle). Expected Square:add(Square)
rs.add(new Square());
重要的部分是表达式rs
和new Square()
的编译时类型。
rs
仅声明为Rectangle
,因此编译器将查看Rectangle
及其超类声明的方法:
public void add(Figure f)
public void add(Rectangle r)
表达式new Square()
的类型为Square
,因此两种方法都适用 - 但第二种方法更具有特定。
因此,编译器将在add(Rectangle)
引用的对象上调用rs
。这就是编译时的一面。
在执行时,rs
的值引用Square
的实例 - 但Square
不会覆盖add(Rectangle)
,因此选择的方法是Rectangle
中的实现{1}}:
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
),前两种方法适用,但第三种方法不适用。因此,再次在编译时选择add(Rectangle)
(因为它比add(Figure)
更具体)。
同样,ss
的执行时间类型为Square
,但不会覆盖add(Rectangle)
,因此会使用Rectangle
中的实现。
如果这里的任何内容令人困惑,请告诉我 - 如果您可以具体说明哪一部分会很棒。
答案 1 :(得分:3)
rs.add(new Square());
声明的rs类型是Rectangle。因此,它查看Rectangle中的方法以及所有采用Square或与Square兼容的类型作为参数的超类。最具体的一个是add(Rectangle)
,因为Square是一个Rectangle,因为Rectangle比图更具体。
Square ss = new Square();
ss.add(rs);
在Square和所有超类中查找方法add(Rectangle)
。选择Rectangle.add(Rectangle)
,因为Square.add(Square)
不适用(矩形不是正方形),Square.add(Figure)
不太具体。