再探Java中的继承加载顺序

来源:互联网 发布:2017年春运大数据 编辑:程序博客网 时间:2024/05/24 04:07
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方法。所以说编译的时候会检查你的语法是否正确,不是说不用就检查了,编译时能发现的错误,不会拖延到运行时才知道

0 0
原创粉丝点击