Java重载方法选择

时间:2013-02-03 19:33:28

标签: java overloading

我试图了解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中指定,但我不明白。

2 个答案:

答案 0 :(得分:19)

  

但是,我不理解示例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,因此两种方法都适用 - 但第二种方法更具有特定

因此,编译器将在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)不太具体。