关于Java编译时和运行时的差异
//有兴趣的人,试试自己的基础,看看这个程序输出的是什么?//第一次解析,难免有点错漏,欢迎阅读者能指出我的错误,并与我分享,大家共同进步! 本人语文水平not good, 错别字就不说了 。。
//关注本人CSDN博客:http://my.csdn.net/erix1991
class Base { private int a = 2; public Base() { this.display(); }public void display() { System.out.println(a); }}
class Derived extends Base { private int a = 22; public Derived() { //super(); a = 222;}public void display() { System.out.println(a); }}
public class TestO {public static void main(String[] args) {new Derived();}}
//输出的是什么? 2, 22, 222? 都是错,答案输出的是0; 这是为什么?
首先明白一点,子类继承父类,如果有多个同名的实例变量,但是子类的同名实例并不能覆盖父类的实例变量 而且子类在堆空间里面分配两个 a实例的变量,而不是一个! 对于Java的构造函数,很多人都吧它理解成Java的对象都是通过构造函数来创建,其实这是错的,其实Java的构造函数只负责做一件事,就是执行对象的实例变量进行初始化! 在类被虚拟机加载到虚拟机里的时候,对象所占的内存已经被分配下来了,对于基本类型的变量是0或者是false; 对于引用类型的变量,默认的就是null;
我们再来看看这个程序执行的顺序吧。
1,首先Derived 这个类被加载到虚拟机,主函数执行new Derived()在堆内存分配空间,因为Derived 继承与Base,那么内存里应该有两份a的实例变量,它们的默认值都是0
2,Derived子类执行构造函数初始化,我们知道,子类初始化,必先执行父类的构造函数,这个程序里隐含了super()的父类构造函数在子类的构造函数里 3,执行super(),调用父类的构造函数,此时执行this.display(),那么这个this指向的是什么呢? 答案是Derived! 为什么不是Base;因为这个父类的构造函数时通过Derived对象来调用,那么这个this当然是Derived的!
4,那么执行this.display()那么当然输出的是0里,因为Derived的a 还没有来的及初始化,在内存空间的默认值还是0; 那么需要解析的是,在Java里,当变量的编译时和运行时类型是不同的,系统在调用它的实例变量和实例方法时存在上述的差异, 就这个程序来说,在父类里,编译的时候,this.display(),这个this是父类,但是当运行的时候,那么this就变成子类的引用了