类加载顺序

public class ClassLoaderOrder {
    public static void main(String[] args) {
        Parent parent = new Child();
        parent.eat();
    }
}

class Parent {

    ParentParameter2 parentParameter2 = new ParentParameter2();
    ParentParameter parentParameter = new ParentParameter();

    public Parent() {
        System.out.println("Parent类构造方法");
    }

    {
        System.out.println("parent 普通代码块代码");
    }

    static {
        System.out.println("parent 静态代码块代码");
    }


    public static void run(){
        System.out.println("parent 静态方法");
    }

    public void eat() {
        System.out.println("parent 普通方法");
    }
}

class Child extends Parent {
    ChildParameter childParameter = new ChildParameter();

    public Child() {
        System.out.println("Child类构造方法");
    }

    {
        System.out.println("child 普通代码块代码");
    }

    static {
        System.out.println("child 静态代码块代码");
    }

    public static void run(){
        System.out.println("child 静态方法");
    }

    @Override
    public void eat() {
        System.out.println("child 普通方法");
    }
}

class ParentParameter {
    public ParentParameter() {
        System.out.println("parent成员参数");
    }
}
class ParentParameter2 {
    public ParentParameter2() {
        System.out.println("parent成员参数2");
    }
}
class ChildParameter {
    public ChildParameter() {
        System.out.println("Child成员参数");
    }
}

/*
parent 静态代码块代码
child 静态代码块代码
parent成员参数2
parent成员参数
parent 普通代码块代码
Parent类构造方法
Child成员参数
child 普通代码块代码
Child类构造方法
child 普通方法
*/


/**
 * 由此可见当涉及到继承时其父类和子类加载顺序为:
 *  父类静态代码块-->子类静态代码块-->父类成员变量(当有多个时,按顺序加载)-->父类普通代码块-->父类构造函数-->
 *      子类成员变量(当有多个时,按顺序加载)-->子类普通代码块-->子类构造函数
 */

而当遇到成员变量是静态,且静态代码块中引用了成员变量等复杂情况时,加载顺序是如何?

package xyz.zeling.test.demo;

/**
 * @Auther: lvqiang
 * @Date: 2020/01/10/16:07
 * @Description: 类中内容加载顺序
 */
public class ClassLoaderOrder2 {

    public static void main(String[] args) {
        Singleton.getInstance();
        System.out.println("Singleton value1:" + Singleton.value1);
        System.out.println("Singleton value2:" + Singleton.value2);

        Singleton2.getInstance2();
        System.out.println("Singleton2 value1:" + Singleton2.value1);
        System.out.println("Singleton2 value2:" + Singleton2.value2);
    }
}

class Singleton {
    static {
        System.out.println(Singleton.value1 + "\t" + Singleton.value2 + "\t" + Singleton.singleton);
        //System.out.println(Singleton.value1 + "\t" + Singleton.value2);
    }

    private static Singleton singleton = new Singleton();
    public static int value1 = 5;
    public static int value2 = 3;

    private Singleton() {
        value1++;
        value2++;
    }

    public static Singleton getInstance() {
        return singleton;
    }

    int count = 10;

    {
        System.out.println("count = " + count);
    }
}

class Singleton2 {
    static {
        System.out.println(Singleton2.value1 + "\t" + Singleton2.value2 + "\t" + Singleton2.singleton2);
    }

    public static int value1 = 5;
    public static int value2 = 3;
    private static Singleton2 singleton2 = new Singleton2();
    private String sign;

    int count = 20;

    {
        System.out.println("count = " + count);
    }

    private Singleton2() {
        value1++;
        value2++;
    }

    public static Singleton2 getInstance2() {
        return singleton2;
    }
}

/*
-----------------------------------------------------------------------------------------
运行结果:
00null
count = 10
Singleton value1:5
Singleton value2:3
00null
count = 20
Singleton2 value1:6
Singleton2 value2:4
-----------------------------------------------------------------------------------------
*/
  1. 对于静态代码块:

    static {
            System.out.println(Singleton2.value1 + "\t" + Singleton2.value2 + "\t" + Singleton2.singleton2);
        }
    

    由于value1、value2、singleton2 是类静态成员变量,会在类加载机制的准备阶段为静态的类型赋该类型的默认值(即int 为0, 类类型的为null), 而根据之前加载顺序,静态代码块是先于类成员变量的 ,所以此时输出的值依旧还是类在准备阶段的默认值。

  2. 对于value1输出5,value2输出3

        private static Singleton singleton = new Singleton();
        public static int value1 = 5;
        public static int value2 = 3;
    

    Singleton为静态类型, 其特点是只能初始化一次,此时已经将5 ,3 赋值 。 后面 获得的也是这个singleton实体类 , 所以输出结果是 5 3。

  3. 对于Singleton 和 Singleton2 的输出结果不同。

        public static Singleton singleton = new Singleton();
        public static int value1 = 5;
        public static int value2 = 3;
        
        
        public static int value1 = 5;
        public static int value2 = 3;
        private static Singleton2 singleton2 = new Singleton2();
    

    因为二者的静态的Singleton成员对象 实例和value1 的顺序不一致导致。

    Singleton2是 由于先进行了赋值 ,然后执行了构造方法进行了++ 所以输出结果是 6 4。而Singleton是 5 3