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)"); }
}

我在这里学到的是

  • 方法签名根据编译时数据类型确定
  • 调用的实际方法取决于调用该方法的对象的动态类型。

基于此,前两次调用的结果符合预期。但是,我不明白示例 3 和 4 的结果。

好像是java语言规范里规定的,但是没看懂。

4

2 回答 2

20

但是,我不明白示例 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

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是 type Square,并且rs是 type Rectangle(编译时类型,记住)。

声明的方法Square及其超类是:

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

由于编译时类型rs是 only Rectangle(not Square),所以前两种方法适用,但第三种方法不适用。因此,再次add(Rectangle)在编译时选择(因为它比 更具体add(Figure))。

同样,执行时间类型ssSquare,它不会覆盖add(Rectangle),因此Rectangle使用了 in 的实现。

如果这里有什么令人困惑的地方,请告诉我——如果你能具体说明哪一部分,那就太好了。

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

rs 的声明类型是矩形。因此,它查看 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)不适用(矩形不是正方形),并且Square.add(Figure)不太具体。

于 2013-02-03T19:40:14.667 回答