我试图让我的头一轮的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());
最重要的部分是在编译时类型的表达式的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
是类型的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的声明类型为矩形。 因此,着眼于矩形的方法和所有超服用或方作为参数与广场相兼容的类型。 最具体的一个是add(Rectangle)
因为广场是矩形,并且由于矩形比图更加具体。
Square ss = new Square();
ss.add(rs);
寻找一个方法add(Rectangle)
在广场和所有超类。 Rectangle.add(Rectangle)
被选择,因为Square.add(Square)
不适用(一个矩形不是正方形),和Square.add(Figure)
是较不具体。