【问题标题】:Java overloading method selectionJava重载方法选择
【发布时间】:2013-02-03 19:33:27
【问题描述】:

我试图弄清楚 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里指定的,不过没看懂。

【问题讨论】:

  • 作为这个作业问题的作者,我可以确认提供的答案是正确的。

标签: java overloading


【解决方案1】:

但是,我不明白示例 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,因此这两种方法都适用 - 但第二种方法更具体

因此编译器将对rs 所引用的对象调用add(Rectangle)。这就是编译时方面的内容。

在执行时,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);

再次,让我们考虑一下所涉及的编译时类型...ssSquare 类型,rsRectangle 类型(请记住编译时类型)。

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中的实现。

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

【讨论】:

    【解决方案2】:
    rs.add(new Square());
    

    rs 的声明类型是矩形。因此,它着眼于 Rectangle 中的一个方法以及所有采用 Square 或与 Square 兼容的类型作为参数的超类。最具体的是add(Rectangle),因为 Square 是一个 Rectangle,而且 Rectangle 比 Figure 更具体。

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

    在 Square 和所有超类中查找方法 add(Rectangle)。选择了Rectangle.add(Rectangle),因为Square.add(Square) 不适用(矩形不是正方形),并且Square.add(Figure) 不太具体。

    【讨论】:

      猜你喜欢
      • 2013-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-09
      • 1970-01-01
      • 1970-01-01
      • 2020-02-13
      • 1970-01-01
      相关资源
      最近更新 更多