记得在学校初学java时讲过,当时也懂了,不过今天看到一个问题时竟然又看不懂,理解不了了....果断重新梳理了一遍。先上题:
class T implements Cloneable{
public static int k = 0;
public static T t1 = new T("t1");
public static T t2 = new T("t2");
public static int i = print("i");
public static int n = 99;
public static String s = "s";
public int j = print("j");
{
print("构造快");
}
static {
print("静态块");
}
public T(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n + " s="+ s);
++n; ++ i;
}
public static int print(String str){
System.out.println((++k) +":" + str + " i=" + i + " n=" + n + " s="+ s);
++n;
return ++ i;
}
public static void main(String[] args){
System.out.println("main");
T t = new T("init");
}
}
然后上输出结果:
1:j i=0 n=0 s=null
2:构造快 i=1 n=1 s=null
3:t1 i=2 n=2 s=null
4:j i=3 n=3 s=null
5:构造快 i=4 n=4 s=null
6:t2 i=5 n=5 s=null
7:i i=6 n=6 s=null
8:静态块 i=7 n=99 s=s
main
9:j i=8 n=100 s=s
10:构造快 i=9 n=101 s=s
11:init i=10 n=102 s=s
先初始化静态变量跟静态块,然后是实例化过程中先初始化成员变量跟构造块,然后是构造函数调用。(静态块,静态属性或者成员变量都是按照申明顺序)
按上述流程,我们分析代码:
首先,类装载,初始化静态类跟静态块
所以执行第二行初始化k,
接下来第三行,初始化T对象,
初始化T对象就到了第9行,此时int 类型 i,n 都未赋值,默认为0,String类型s 则为null,所以打印出 1:j i=0 n=0 s=null
然后接下来就是10-12行的构造块,因为上一行i,n 都自增了,所以打印出 2:构造快 i=1 n=1 s=null
成员变量跟构造块初始化完毕,调用构造函数,于是执行18-21,打印出 3:t1 i=2 n=2 s=null
OK,t1对象初始化完毕了,t2对象同理,不再赘述。
然后就到了第5行,执行变量i的赋值,打印出 7:i i=6 n=6 s=null
然后执行第6行,变量n赋值为99,注意,n在这之前是6,现在变为99了,接下来的打印能发现区别。
第7行,s赋值为“s”,变量s不再为null了
然后就到静态块了,打印结果为 8:静态块 i=7 n=99 s=s 看n 跟s的变化;
OK,执行到这完成了一个阶段的初始化了,可以理解为是类的装载,然后就到程序的入口函数main方法中来了 29-32
main函数中先打印了main 然后实例化了个T对象,T对象的实例化同t1 t2的实例化过程,
打印结果自然为main
9:j i=8 n=100 s=s
10:构造快 i=9 n=101 s=s
11:init i=10 n=102 s=s
=================================华丽的分割线=====================================
再来个蛋疼的例子学习下:
1. package test01;
2.
3. class Singleton {
4.
5. public static Singleton singleton = new Singleton();
6. public static int a;
7. public static int b = 0;
8.
9. private Singleton() {
10. super();
11. a++;
12. b++;
13. }
14.
15. public static Singleton GetInstence() {
16. return singleton;
17. }
18.
19. }
20.
21. public class MyTest {
22.
23. /**
24. * @param args
25. */
26. public static void main(String[] args) {
27. Singleton mysingleton = Singleton.GetInstence();
28. System.out.println(mysingleton.a);
29. System.out.println(mysingleton.b);
30. }
31.
32. }
答案是a=1,b=0。
分析下流程:首先对Singleton的所有的静态变量分配空间,赋默认的值,所以在这个时候,singleton=null、a=0、b=0。注意b的0是默认值,并不是我们赋的0。
然后对静态变量赋值。singleton = new Singleton();调用构造方法。构造方法里面a=1、b=1。之后接着顺序往下执行,a没有赋值,保持原状a=1。b被赋值了,b原先的1被覆盖,b=0。所以结果就是这么来的。
================================继承情况下=========================================
class Test{
static{
System.out.println("父类static 块 1 执行");
}
static Sample staticSam1=new Sample("父类 静态成员staticSam1初始化");
Sample sam1=new Sample("父类 sam1成员初始化");
static Sample staticSam2=new Sample("父类 静态成员staticSam2初始化");
static{
System.out.println("父类 static 块 2 执行");
}
Test()
{
System.out.println("父类 Test默认构造函数被调用");
}
Sample sam2=new Sample("父类 sam2成员初始化");
}
class Sample
{
Sample(String s)
{
System.out.println(s);
}
Sample()
{
System.out.println("Sample默认构造函数被调用");
}
}
class TestSub extends Test
{
static Sample staticSamSub=new Sample("子类 静态成员staticSamSub初始化");
TestSub()
{
System.out.println("子类 TestSub 默认构造函数被调用");
}
Sample sam1=new Sample("子类 sam1成员初始化");
static Sample staticSamSub1=new Sample("子类 静态成员staticSamSub1初始化");
static{System.out.println("子类 static 块 执行");}
Sample sam2=new Sample("子类 sam2成员初始化");
}
结果为:
父类static 块 1 执行
父类 静态成员staticSam1初始化
父类 静态成员staticSam2初始化
父类 static 块 2 执行
子类 静态成员staticSamSub初始化
子类 静态成员staticSamSub1初始化
子类 static 块 执行
父类 sam1成员初始化
父类 sam2成员初始化
父类 Test默认构造函数被调用
子类 sam1成员初始化
子类 sam2成员初始化
子类 TestSub 默认构造函数被调用
可以看到,继承情况下先初始化父类静态,然后子类静态,然后父类成员变量,父类构造函数,然后是子类成员变量跟构造函数。