假设您有两个类:
public abstract class X {
public abstract void insert(Object item);
}
public class Y extends X {
protected Object a;
public void insert(Object item) {
a = item;
}
}
当您尝试以下操作时:
X x = new Y();
x.insert(5);
一切都很好。但是,当你还添加
x.a;
你为什么要这样做:
((Y) x).a;
最后一行?
提前谢谢!
答案 0 :(得分:4)
但是,编译器是否应该认识到x的动态类型实际上是Y?
不,编译器不会分析程序以确定变量的动态类型。在编译时,它仅适用于静态类型。
对于第二行似乎理解这一点,因为insert方法实际上最终给了x一个“a”的值。
方法解析在运行时完成,可以进行动态输入。这不是编译器执行分辨率,而是运行时。
答案 1 :(得分:0)
方法/字段分辨率基于引用变量的类型(在这种情况下为X)完成。 X上不存在'a',因此您必须转换为Y以告诉编译器将该引用视为Y引用,因此可以解析'a'。
答案 2 :(得分:0)
动态绑定在这里无关紧要。静态绑定是重要的事情。
当您定义对象eas X
时,您的对象具有X x = ...
类型的静态绑定。编译器不知道该类型中的任何a
。
答案 3 :(得分:0)
假设你有这个代码:
public abstract class X {
public abstract void insert(Object item);
}
public class Y extends X {
protected Object a;
public void insert(Object item) {
a = item;
}
}
public class Z extends X {
public void insert(Object item) {
/* nothing */
}
}
// method signature : public X someSecretBlackBoxMethod()
X x = someSecretBlackBoxMethod();
现在,someSecretBlackBoxMethod
方法返回扩展X
的类的具体实例,对吧?那是哪一个,Y
或Z
?
好吧,编译器也不知道。这就是编译器无法解析x.a
的原因。但是,如果将其强制转换为Y
(即((Y)x).a
),则编译器知道 x
应该是{的实例{1}}因此,了解该属性。现在,在运行时,如果Y
不是 x
的实例,那么您获得了ClassCastException
。