紧接着上一次博客 类的初始化顺序(一)
上次只是简单的介绍了初始化顺序,但是具体事例一般都很复杂。
比如:如果变量或者是代码块中有对象的实例化或者是方法的调用。
以下总结仅适用于一个类(不存在其他类的调用)
如果静态变量或静态代码块中是方法的调用,很简单:执行方法。
但是有实例化对象的情况就比较复杂了。
- 非静态成员变量和非静态初始化代码块中调用实例化,运行报错。因为此时实例化还未完成,会陷入死循环(会循环调用非静态成员变量和非静态代码块)
- 静态成员变量和静态初始化代码块中调用实例化。运行成功。执行该类的非静态成员变量和非静态初始化代码块。
在情况2的基础上,
a) 如果该类的非静态成员变量和非静态初始化代码块中调用了静态变量。
如果顺序靠前已经初始化,直接调用。
如果顺序不靠前,不初始化 。b) 如果该类的成员调用了非静态成员变量,直接初始化。
例一:
main方法中调用new Father();
class Father {
public static Father s1 = new Father();
public static int i = print();
public static int j = 11;
// public Father k = new Father();//运行报错
public Father k = null;
public int m = print("m");
public int n = 99;
static {
//能调用的静态成员变量肯定都已经初始化了
System.out.println("父类静态代码块初始化");
System.out.println("s1="+s1+" i="+i+" j="+j);
}
{
//能调用的非静态成员变量肯定都已经初始化了
System.out.println("父类代码块初始化");
// k = new Father();//运行报错,会循环调用非静态成员变量和代码块
System.out.println("k="+k+" m="+m+" n="+n);
}
public static int print() {
System.out.println("静态方法");
return ++i;
}
public int print(String str) {
System.out.println("普通方法");
return ++i;
}
public Father() {
System.out.println("无参构造函数初始化完成");
System.out.println("s1="+s1+" i="+i+" j="+j);
System.out.println("k="+k+" m="+m+" n="+n);
}
}
输出结果:
普通方法
父类代码块初始化
k=null m=1 n=99//初始化非静态代码块和成员变量
无参构造函数初始化完成
s1=null i=1 j=0//对应情况a) 此时静态变量并没有初始化
k=null m=1 n=99//1.public static Father s1 = new Father();调用输出结束
静态方法 //2.public static int i = print();调用输出结束
父类静态代码块初始化
s1=com.shu.myokgo.Father@50134894 i=2 j=11//3.静态初始化代码块调用输出结束
普通方法
父类代码块初始化
k=null m=3 n=99 //4.初始化非静态代码块和成员变量
无参构造函数初始化完成
s1=com.shu.myokgo.Father@50134894 i=3 j=11
k=null m=3 n=99//4.初始化构造函数
例二:
在上面的Father中如果存在public static Father s2 = new Father();情况又会是怎样的?
结论:仍然会调用该类的非静态成员变量和非静态初始化代码块。
代码:
class Father {
public static Father s1 = new Father();
public static Father s2 = new Father();
public static int i = print();
public static int j = 11;
// public Father k = new Father();//运行报错
public Father k = null;
public int m = print("m");
public int n = 99;
static {
//能调用的静态成员变量肯定都已经初始化了
System.out.println("父类静态代码块初始化");
System.out.println("s1="+s1+" i="+i+" j="+j);
}
{
//能调用的非静态成员变量肯定都已经初始化了
System.out.println("父类代码块初始化");
// k = new Father();//运行报错,会循环调用非静态成员变量和代码块
System.out.println("k="+k+" m="+m+" n="+n);
}
public static int print() {
System.out.println("静态方法");
return ++i;
}
public int print(String str) {
System.out.println("普通方法");
return ++i;
}
public Father() {
System.out.println("无参构造函数初始化完成");
System.out.println("s1="+s1+" i="+i+" j="+j);
System.out.println("k="+k+" m="+m+" n="+n);
}
}
输出结果:
普通方法
父类代码块初始化
k=null m=1 n=99
无参构造函数初始化完成
s1=null i=1 j=0
k=null m=1 n=99//1.public static Father s1 = new Father();调用结束
普通方法
父类代码块初始化
k=null m=2 n=99
无参构造函数初始化完成
s1=com.shu.myokgo.Father@50134894 i=2 j=0
k=null m=2 n=99//2.public static Father s2 = new Father();调用结束
静态方法
父类静态代码块初始化
s1=com.shu.myokgo.Father@50134894 i=3 j=11
普通方法
父类代码块初始化
k=null m=4 n=99
无参构造函数初始化完成
s1=com.shu.myokgo.Father@50134894 i=4 j=11
k=null m=4 n=99
例三:
据说是阿里巴巴的题,试着验证一下结论吧!
public class TestVar {
public static int k = 0;
public static TestVar t1 = new TestVar("t1");
public static TestVar t2 = new TestVar("t2");
public static int i = print("i");
public static int n = 99;
public int j = print("j");
{
print("构造");
}
static {
print("静态");
}
public TestVar(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++i;
++n;
}
public static int print(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++n;
return ++i;
}
public static void main(String[] args) {
TestVar t = new TestVar("init");
}
}
结果:
1:j i=0 n=0
2:构造 i=1 n=1
3:t1 i=2 n=2
4:j i=3 n=3
5:构造 i=4 n=4
6:t2 i=5 n=5
7:i i=6 n=6
8:静态 i=7 n=99
9:j i=8 n=100
10:构造 i=9 n=101
11:init i=10 n=102