java基础:继承关系类加载顺序问题
2017-05-31 16:02
423 查看
/** * Created by fei on 2017/5/31. */ public class SonClass extends ParentClass{ public SonClass(){ System.out.println("SonClass's constructor"); } { System.out.println("SonClass's block");} static { System.out.println("SonClass's static block "); } public static void main(String[] args) { System.out.println("------ main start ------ "); new SonClass(); System.out.println("------ main end ------ "); } } class ParentClass{ public ParentClass(){ System.out.println("ParentClass's constructor"); } { System.out.println("ParentClass's block");} static { System.out.println("ParentClass's static block "); } }
运行结果:
ParentClass's static block SonClass's static block ------ main start ------ ParentClass's block ParentClass's constructor SonClass's block SonClass's constructor ------ main end ------
根据运行结果,一目了然,在执行 main 方法中 new SonClass() 之前,就在类加载之后执行了类中 static 代码块。然后再进入main方法,执行new操作,当然显而易见,在执行new子类操作的时候,是要先进行其父类的构造,即先执行父类的构造代码块(代码中只用大括号包裹的那段代码)以及构造函数 ,然后再执行子类的构造代码块以及构造函数。
修改一下代码,再来看看运行的结果:
/** * Created by fei on 2017/5/31. */ public class SonClass extends ParentClass{ ParentClass parentClass; public SonClass(){ System.out.println("1"); } public SonClass(String name){ System.out.println("2"); this.name = name; parentClass = new ParentClass("FEI"); } public static void main(String[] args) { System.out.println("------ main start ------ "); new SonClass("fei"); System.out.println("------ main end ------ "); } } class ParentClass{ String name ; public ParentClass(){ System.out.println("3"); } public ParentClass(String name){ System.out.println("4"); this.name = name ; } }
运行的顺序是:
------ main start ------ 3 2 4 ------ main end ------
第一个规则:子类的构造过程中,必须调用其父类的构造方法。一个类,如果我们不写构造方法,那么编译器会帮我们加上一个默认的构造方法(就是没有参数的构造方法),但是如果你自己写了构造方法,那么编译器就不会给你添加了,所以有时候当你new一个子类对象的时候,肯定调用了子类的构造方法,但是如果在子类构造方法中我们并没有显示的调用基类的构造方法,如:super(); 这样就会调用父类没有参数的构造方法。
第二个规则:如果子类的构造方法中既没有显示的调用基类构造方法,而基类中又没有无参的构造方法,则编译出错,所以,通常我们需要显示的:super(参数列表),来调用父类有参数的构造函数,此时无参的构造函数就不会被调用。
总之,一句话:子类没有显示调用父类构造函数,不管子类构造函数是否带参数都默认调用父类无参的构造函数,若父类没有则编译出错。
还是两个类,我们再更改一下。
/** * Created by fei on 2017/5/31. */ public class SonClass extends ParentClass{ private String name = "SonClass"; public SonClass() { printName(); } public void printName() { System.out.println("SonClass print name: " + name); } public static void main(String[] args){ new SonClass(); } } class ParentClass{ private String name = "ParentClass"; public ParentClass() { //System.out.println(this.getClass()); printName(); } public void printName() { System.out.println("ParentClass print name: " + name); } }
看了上面的两个例子,最后这个例子就很容易被迷惑,可能有人会觉得运行结果是类似这样的:
ParentClass print name: ParentClass SonClass print name: SonClass
或者是:
ParentClass print name: SonClass S aa60 onClass print name: SonClass
但真正的结果是这样的:
SonClass print name: null SonClass print name: SonClass
为什么会这样,其实只要打开代码中父类构造器中的这句注释,就很容易理解了:System.out.println(this.getClass())
结果是:
class SonClass
没错,父类中的this引用是子类实例对象,所以在父类构造函数里调用的还是子类的printName()方法。具体原因也并我能十分肯定,我个人浅见,是因为虽然我们调用了父类的构造方法,但是我们并没有实例化出父类的实例对象,所以this还是指向的是子类的引用。
相关文章推荐
- 详解java中继承关系类加载顺序问题
- Java中的继承关系的加载顺序
- java的继承关系中对象的加载和初始化顺序
- Java继承关系中静态代码块的顺序问题
- 【Thinking in Java真题精选】2. 存在继承关系时的类加载顺序
- Java类被加载时执行的顺序问题
- 对于Java类加载过程中的顺序问题探究
- java基础之问题:请说出hashCode方法、equals方法、HashSet、HashMap之间的关系
- java基础--多态-域与静态方法2--类中各字段方法的加载顺序
- java 类中变量,方法加载顺序和造成的问题。
- 关于java文件加载和初始化顺序问题分析
- Java笔记(十二)……类中各部分加载顺序及存放位置问题
- java 继承类加载顺序
- JAVA继承关系中的初始化顺序
- java继承时候类的运行顺序问题
- Java类被加载时执行的顺序问题
- 复习一下Java中继承关系的类的初始化顺序
- java基础 -- Java 类中各成分加载顺序 和 内存中的存放位置
- Java 继承加载顺序 以及 多态中变量和方法
- Java继承中父类和子类的加载顺序