Java 指向子类对象的超类ref的类类型是什么?
我有以下代码:Java 指向子类对象的超类ref的类类型是什么?,java,class,reference,subclass,superclass,Java,Class,Reference,Subclass,Superclass,我有以下代码: 1. public class Tester 2. { 3. public static void main(String[] args) 4. { 5. A a = new B(); 6. System.out.println(a.getClass()); //Prints class B 7. System.out.println(a instanceof A); //Prints
1. public class Tester
2. {
3. public static void main(String[] args)
4. {
5. A a = new B();
6. System.out.println(a.getClass()); //Prints class B
7. System.out.println(a instanceof A); //Prints true
8. System.out.println(a instanceof B); //Prints true
9. System.out.println(a.valA); //Prints 1
10. System.out.println(a.valB); //Compilation error
11.
12. }
13. }
14.
15. class A
16. {
17. int valA=1;
18. }
19.
20. class B extends A
21. {
22. int valB=2;
23. }
第6行显示a
类型为B类
。但是,当它到达第10行时,编译器会产生一个错误:位置:a类型的变量a
所以我的问题是:现在a
的类类型到底是什么?为什么getClass()
显示它属于class B
类型,而编译器在编译过程中将它抱怨为A
类型
此外,既然a instanceof B
是真的,为什么我不能访问valB
为了让事情更清楚:
EDIT:我运行了以下语句:
System.out.println(a)代码>输出为B@36d98810
以某种方式证明执行了类B
的toString()
方法。既然变量a
可以访问类B
中的toString()方法,为什么它不能访问同样位于类B
中的valB
?a
不是对象。这是一个变量
变量的类型为A
。变量值在执行时引用的对象类型为B
编译器根据所涉及表达式的编译时类型(本例中的变量)解析所有内容。当试图在编译时类型A
内解析名称valB
时,它找不到任何东西-因此出现错误。这是类继承、接口等的基本属性。
类“A”没有变量“valB”。
如果要在类“B”中使用变量“valB”,则应首先将类“A”强制转换为“B”
尝试:
您应该知道对象类型和实例类型之间的区别。第一个是在编译类型时确定的,在运行时它会尽力保证该类型的安全。实例类型是实例化对象的类
A a; //this is an object type
new B(); //this is an instance type
A a = new B(); //all together, but a is of type A, having instance of type B.
您需要记住,编译和执行是两个不同的过程,它们发生在不同的时间,并且具有不同的可用信息。编译器必须预测未来——它必须决定是否能够保证您的代码在未来的运行时有意义。它通过分析代码中对象的类型来实现这一点。另一方面,运行时只需检查事物的当前状态
当您阅读行A=new B()
时,您推断出的有关A
局部变量的信息比编译器的信息要多。编译器基本上只是将其视为A=
。它不会记录用于生成a
值的表达式的内容
事实上,你说的A=…
是在告诉编译器:“嘿,这个A
我将在我程序的其余部分处理的事情,它只是一个A
,不要再假设了。”如果你说的是B A=…
,那么你是在告诉编译器它是一个B
(编译器还看到B在代码的其他地方扩展了A
,因此它知道它也是A
)
从编译器的角度来看,无论a
、a
、a.getClass()
和a.toString()
的类型是什么,后续表达式a
都是合法的:instanceof
操作符和getClass()
和toString()
方法是为所有对象定义的(编译器不需要预测这些表达式在运行时将产生什么值,只需要它们分别产生true
或false
、一些类
和一些字符串
)
但是当你谈到a.valA
和a.valB
时,编译器实际上必须做一些实际的工作。它需要证明或保证a
对象在运行时将有一个valA
和一个valB
字段。但是既然你之前明确告诉它,只需假设a
是一个A
,它无法证明在运行时它将有一个valB
字段
现在,稍后,在执行时,JVM有了更多信息。当它计算a.getClass()
时,它实际上会查找“隐藏”的具体类对于a
并返回它。类似地,对于实例B
,它查找具体的类,因此该表达式的结果是true
a.toString()
的工作原理类似。在运行时,JVM知道a
引用的东西实际上是aB
,因此它执行B
的toString
方法。加州大学伯克利分校的Jonathan Shewchuk教授解释了跟踪。18分钟开始。(如果链接改变,只需谷歌搜索CS61B第15讲:更多Java)
简而言之,变量有两种类型:静态类型和动态类型
Static type is its Type at compile time
Dynamic type is its Type at run time.
在你的例子中
A a = new B();
a的静态类型为a,动态类型为B
In Java a variable gets its non static methods from dynamic type
(if the method exists in both the parent and child class)
and
its fields and static methods from the static type.
只有在子类中重写了该方法时,C#中才是如此
更新:
线路
告诉您a的动态类型是a的类型还是a的子类
更新2:
一个例子说明了这一点
public class PlayGround {
public static void main(String[] args) {
Animal a = new Dog();
System.out.print(a.name);// displays animal
System.out.print("\r\n");
a.MakeStaticSound();// displays static animal sound
System.out.print("\r\n");
a.MakeSound();// displays bow wow
}
}
class Animal {
public String name = "animal";
public void MakeSound() {
System.out.print("animal sound");
}
public static void MakeStaticSound() {
System.out.print("static animal sound");
}
}
class Dog extends Animal {
public String name = "dog";
public void MakeSound() {
System.out.print("bow wow");
}
public static void MakeStaticSound() {
System.out.print("static bow wow");
}
}
请注意,调用a.MakeStaticSound()的可读性和首选方法是Animal.MakeStaticSound()编译器只知道a
类型为a
,因此不能推断它将有一个名为valB
的字段
a instanceof A
public class PlayGround {
public static void main(String[] args) {
Animal a = new Dog();
System.out.print(a.name);// displays animal
System.out.print("\r\n");
a.MakeStaticSound();// displays static animal sound
System.out.print("\r\n");
a.MakeSound();// displays bow wow
}
}
class Animal {
public String name = "animal";
public void MakeSound() {
System.out.print("animal sound");
}
public static void MakeStaticSound() {
System.out.print("static animal sound");
}
}
class Dog extends Animal {
public String name = "dog";
public void MakeSound() {
System.out.print("bow wow");
}
public static void MakeStaticSound() {
System.out.print("static bow wow");
}
}