再探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方法。所以说编译的时候会检查你的语法是否正确,不是说不用就检查了,编译时能发现的错误,不会拖延到运行时才知道

原文地址:https://www.cnblogs.com/zhangmingzhao/p/7256673.html