再探Java中的继承加载顺序
public class test2 { static class a { int x = 999; int y = 999; { System.out.println("a--父类非静态方法"); } static { System.out.println("a--父类静态方法"); } // public a() { // System.out.println("a--执行a类无参构造方法"); // } public a(int x) { System.out.println("a--执行父类有参构造方法"); } public void print() { System.out.println("a--我是父类的打印方法"); } } static class b extends a { int x = 1; int y; { System.out.println("b--子类非静态方法"); } static { System.out.println("b--子类静态方法"); } // public b() { // super(); // System.out.println("b--执行b类无参构造方法"); // //y = -1; // } public b(int x) { super(1); System.out.println("b--执行子类有参构造方法"); } public void print() { System.out.println("b--在子类中调用父类的super方法"); super.print(); System.out.println("b--我是子类的打印方法"); } } public static void main(String[] args) { // TODO Auto-generated method stub int x = 0; new b(x); //a.print(); } }
如图,这样加载顺序,先加载的都是静态块,先父类后子类。然后加载父类的非静态方法和构造器,然后子类的非静态方法和构造器
执行顺序大体上可以说是先父类后子类,父类static域 ==》子类static域 ==》父类数据成员域 ==》父类构造器 ==》子类数据成员域 ==》子类构造器。而且从结果中我们还可以看到,无论实例化多少个对象,static 域仅有一份,而且只执行一次。
注意第三十九行代码:这里显式调用了父类的有参构造,不加的话会默认调用无参的,如果父类没写无参的就会报错
第二个:
public class test1 { static class a { int x = 999; int y = 999; { System.out.println("a--父类非静态方法"); } static { System.out.println("a--父类静态方法"); } public a() { System.out.println("a--执行a类无参构造方法"); print(); } public a(int x) { System.out.println("a--执行父类有参构造方法"); } public void print() { System.out.println("a--我是父类的打印方法"); } } static class b extends a { int x = 1; int y; { System.out.println("b--子类非静态方法"); } static { System.out.println("b--子类静态方法"); } public b() { System.out.println("b--执行b类无参构造方法"); //y = -1; } public b(int x) { // super(1); //不写是默认生成的super(),无参数的 System.out.println("b--执行子类有参构造方法"); } public void print() { System.out.println("b--在子类中调用父类的super方法"); super.print(); System.out.println("b--我是子类的打印方法"); } } public static void main(String[] args) { // TODO Auto-generated method stub int x = 0; a a1 = new a(x); a1.print(); System.out.println(); b b1 = new b(x); // a.print(); } }
输出如图:
第二个声明了子类的对象,因为print(),在子类中被重写了。所以调用的是子类的重写后的print方法。但是还是可以通过super访问父类的这个被重写的方法。
子类的构造器必须要调用父类的构造器才能完成初始化,默认的是super(),没有参数的,也就是会默认调用父类无参数的构造器
第三个:
public class test1 { static class a { int x = 999; int y = 999; { System.out.println("a--父类非静态方法"); } static { System.out.println("a--父类静态方法"); } // public a() { // System.out.println("a--执行a类无参构造方法"); // print(); // } public a(int x) { System.out.println("a--执行父类有参构造方法"); } public void print() { System.out.println("a--我是父类的打印方法"); } } static class b extends a { int x = 1; int y; { System.out.println("b--子类非静态方法"); } static { System.out.println("b--子类静态方法"); } public b() { super(0); System.out.println("b--执行b类无参构造方法"); //y = -1; } public b(int x) { super(1); //不写是默认生成的super(),无参数的 System.out.println("b--执行子类有参构造方法"); } public void print() { System.out.println("b--在子类中调用父类的super方法"); super.print(); System.out.println("b--我是子类的打印方法"); } } public static void main(String[] args) { // TODO Auto-generated method stub int x = 0; // a a1 = new a(x); // a1.print(); System.out.println(); b b1 = new b(x); // a.print(); } }
如果注释了父类的无参构造,但是子类还有有无参构造,我现在创建的是子类有参的对象,还是会报错。为什么?问了杨学长,语法规定就是这样,就算这个b子类无参构造没有实际加载(打印信息没有打印),只要你写了子类的构造,你就必须要为这个构造方法负责,不管在之后对象有没有用到。注释了父类无参构造的话,可以在b子类无参构造这里加一个super(0),调用父类有参的构造,必须要特别这样声明才行,不声明编译器会找父类无参,无参又没有,所以报错。
编译器按照Java语言的规范把源码编译成字节码文件,然后JVM加载这个类,初始化等一系列操作调用它的main方法。所以说编译的时候会检查你的语法是否正确,不是说不用就检查了,编译时能发现的错误,不会拖延到运行时才知道