java 类实例化及类加载时: 父类、子类中, 静态代码块、构造代码块、静态方法、静态常量等的执行顺序

目录

名词解释:

单个类中的实例化顺序

父子继承类中实例化顺序

      对下述的测试类01,02,03 的输出结果原因是:

      对下述的测试类04,05,06 的输出结果原因是:

测试类01:

测试类02:

测试类03:

测试类04:

测试类05

测试类06


名词解释:

       静态代码块:就是用static修饰的用{}括起来的代码段,可用于对静态属性进行初始化。类加载时会执行

       构造代码块:直接用{}括起来的代码段.对象实例化时候会执行,构造代码块优先于构造函数执行

       构造函数:不再赘述

 

单个类中的实例化顺序

       单个类被实例化时候的执行顺序如下:静态代码块 > 构造代码块 > 构造函数。

 

父子继承类中实例化顺序

     举例如下.

      对下述的测试类01,02,03 的输出结果原因是:

                     静态代码块会在类加载时候执行,构造代码块和构造函数会在类实例化时候执行.

      对下述的测试类04,05,06 的输出结果原因是:

                     可以参考java虚拟机原理 7.2章节的 类加载的时机,现简述如下:

1 遇到new ,getstatic,putstatic,invokestatic ,如果类没有初始化,就要先触发其初始化,

2 如果java.lang.reflect包的方法对类进行反射调用时候,如果类没有进行过初始化,则需要优先触发其初始化

3 如果初始化一个类的时候,其父类还没有初始化,则需要优先触发其父类初始化

4 当虚拟机启动时候,用户需要制定一个要执行的类(包含main()方法的类),虚拟机会优先触发这个主类

5 如果定义一个类的数组,这个类是不会进行初始化的,因为这个数组只有基本的属性,长度等

6 对于静态字段(非静态常量),只有直接定义这个字段的类,才会被初始化.因此,通过其子类来引用父类中定义的静态字段,只会触发父类的初始化,而不会触发子类的初始化.至于是否要触发子类的加载和验证,在虚拟机中没有明确的 规定,这点取决于虚拟机的具体实现.

7 当一个类在初始化时,要求其父类全部已经初始化过了,但是一个接口在初始化时,并不要求其父接口全部都完成了初始化,只有在真正用到父接口时候,才会初始化

 

    

测试父类:

public class SupperClass {
    public SupperClass(){
        System.out.println("父类构造方法");
    }
    static{
        System.out.println("父类静态代码块");
    }
    {
        System.out.println("父类代码块");
    }
    public  static void  pll(){
        System.out.println("父类静态方法");
    }
    public static  int value = 23;
}

 

测试子类:

public class SupperClassExtend extends SupperClass {
    public SupperClassExtend(){
        System.out.println("子类构造方法");
    }
    static {
        System.out.println("子类静态代码块");
    }
    public  static void  pl(){
        System.out.println("子类静态方法");
    }

    {
        System.out.println("子类代码块");
    }

}

测试类01:

public class TestClassLoad {
    public static void main(String[] args) {
//实例化子类
       SupperClassExtend ex = new SupperClassExtend();
    }
}

输出结果为:

父类静态代码块
子类静态代码块
父类代码块
父类构造方法
子类代码块
子类构造方法

输出原因是:

   

测试类02:

public class TestClassLoad {
    public static void main(String[] args) {
//实例化父类
       SupperClass ex = new SupperClass();
    }
}

输出结果为:

父类静态代码块
父类代码块
父类构造方法

测试类03:

public class TestClassLoad {
    public static void main(String[] args) {
//父类的引用指向子类的对象
        SupperClass sc = new SupperClassExtend();
    }
}

输出结果为:

父类静态代码块
子类静态代码块
父类代码块
父类构造方法
子类代码块
子类构造方法

测试类04:

public class TestClassLoad {
    public static void main(String[] args) {
//定义子类或者父类数组(父类数组通子类数组一样,都不会有任何输出)
        SupperClassExtend[] ex = new SupperClassExtend[10];
    }
}

输出结果为空

测试类05

public class TestClassLoad {
    public static void main(String[] args) {
      System.out.println(SupperClassExtend.value);
    }
}

输出结果为:

父类静态代码块
23

测试类06

public class TestClassLoad {
    public static void main(String[] args) {
      System.out.println(SupperClass.value);
    }
}

输出结果为:

父类静态代码块
23

你可能感兴趣的:(java)