Java中子类可以继承父类的属性和方法,那么子类对象就可以直接使用父类对象的属性和方法,实现机制就是,当某个子类对象实例化的时候,会首先实例化一个其父类对象,但这个父类对象对外不可见,只能通过子类中的super来访问;以此类推,父类对象初始化前又会先初始化它的父类对象......直至初始化Object对象为止。这样的效果就是,新建一个类的实例实际上得到的是一个对象的“链条”,通过关键字super连接的对象链条。子类对象就可以通过super来访问到所有它继承到的东西。
为了实现这样的初始化动作,应该在每个类的构造器中所有代码的前面先初始化这个类的直接父类对象。
但是事实上,我们平时写代码的时候,构造器中多数没有写过父类对象初始化的语句,甚至很多时候,连构造器都不写。但是程序依然正常运行,为了一探究竟,我用DJ Java Decompiler工具来反编译class文件,查看内部细节。
Parent类,没有写任何构造器,
反编译该类文件,可以看到,Java编译时看到程序没有写任何构造器,就会自动加上一个“空”的无参构造器,(若程序中已定义构造器,不论有参无参,这个“空”的无参构造器就不会自动产生)
我们现在定义一个子类Son,继承这个Parent类
这里子类Son的构造器中没有写任何的实例化父类的语句,反编译的程序中也没有,但是我们查看class文件内容
可以看到在Son的构造器内部,并不是空的,第二条的指令就是调用父类的构造器 Method void Parent(),相当于Son的构造器里面写了一条super(); 这里编译器自动加的是父类的无参构造器,而不管父类究竟是否有无参构造器,这也正是父类没有无参构造器(程序员写了一个带参数的构造器,编译器就不再自动添加一个“空”的无参构造器)时,子类构造器中若不显示初始化父类对象,编译器就会报错的原因。(因为子类构造器中没有初始化父类对象的语句,所以编译器自动为子类构造器添加了一个调用父类无参构造器的指令,但是父类没有无参构造器,找不到指定的方法,便会报错)
所以正常情况下,我们可以不写构造器(编译器会帮我们加一个),在构造器中我们也不必显示初始化父类对象(编译器会帮我们调用父类无参构造器),但这不代表程序中就真的可以没有。
从上面我总结了一下我对Java初始化和构造器的一些东西,我们可以看到,其实编译器很“智能”,或者说,我们写的程序编译器并没有直接接受,而是做了预处理或优化的工作。结合我之前的学习,编译器的这种“智能”,并不仅限于此,我在使用反编译器查看class文件时还看到过其他的优化过程,这里也写下来,免得忘了。
1. 字符串的拼接
源代码
反编译后
2. 属性初始化
源代码
反编译后
以后发现再补上...