我写了一段代码来了解运行时多态性......
class S{
int i=1;
void m(){
System.out.println("sssssssssssssssssssss");
}
}
public class A extends S{
int i=2;
void m(){
System.out.println("aaaaaaaaaaaaaaaaaaaaaaaa");
}
public static void main(String[] args) {
S a=(S)new A();
System.out.println(a.i);
a.m();
}
}
实例变量受编译时绑定的影响,但是为什么A
的对象的向下转换在这里没有意义?意味着它调用A's
方法而非S's
方法?
答案 0 :(得分:2)
S a = (S)new A();
让我们看看你在这里有什么:
a
,引用类型 S
; A
类型的对象,其中A extends S
; S
类型; a
。在阅读Java时,您必须清楚地了解以下内容:
A
; A
的引用转换为类型为S
的引用。您已将该引用分配给a
。当您在对象上调用方法时,调用的实际方法根本不依赖于引用的类型,而只取决于对象的类型本身。对象的类型为A
,因此调用类型A
中的方法。
另一方面,当您访问实例变量时,多态性不适用,并且引用的类型变得必不可少。使用a.i
,您可以访问超类型i
中声明的S
,并使用((A)a).i
访问来自i
的{{1}}。请注意,类A
拥有两个实例变量,两者都名为A
,您可以单独引用它们。
术语“引用的类型”实际上是更正确的“产生引用的表达类型”的简写。它是纯粹的编译时工件:在运行时没有与引用关联的类型信息,它只是一个位模式。将此与对象的类型进行对比,该对象是纯粹的运行时工件:编译器通常不知道表达式中涉及的对象的类型,它只会使断言关于它。当这样的断言在运行时失败时,结果就是ClassCastException。
答案 1 :(得分:0)
变量a
是类型为S
的引用,其类为A
。当您在该对象上调用m()
时,您将始终在调用类m()
中获取A
的版本,因为这是对象的类,无论哪种类型的变量是引用它。这就是多态性的含义。被调用的m()
版本取决于对象的类,而不是引用表达式的类型。
但是,此对象实际上包含两个名为i
的变量 - 一个在类A
中声明,另一个在类S
中声明。您获得哪一项取决于您使用的类型的引用表达式。由于变量a
的类型为S
,因此表达式a.i
指的是在类S
中声明的那个。