Java重载方法选择

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

但是,我不理解示例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); 

再次,让我们考虑所涉及的编译时类型… 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的实现。

让我知道这里的任何事情是否令人困惑 – 如果你能具体说明哪个部分,那就太棒了。

 rs.add(new Square()); 

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