类加载顺序
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
-----------------------------------------------------------------------------------------
*/
-
对于静态代码块:
static { System.out.println(Singleton2.value1 + "\t" + Singleton2.value2 + "\t" + Singleton2.singleton2); }
由于value1、value2、singleton2 是类静态成员变量,会在类加载机制的准备阶段为静态的类型赋该类型的默认值(即int 为0, 类类型的为null), 而根据之前加载顺序,静态代码块是先于类成员变量的 ,所以此时输出的值依旧还是类在准备阶段的默认值。
-
对于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。
-
对于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