java 类初始化,实例化顺序

来源:互联网 发布:苹果mac能玩什么游戏 编辑:程序博客网 时间:2024/04/30 10:02

记得在学校初学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=null2:构造快   i=1   n=1   s=null3:t1    i=2  n=2   s=null4:j   i=3   n=3   s=null5:构造快   i=4   n=4   s=null6:t2    i=5  n=5   s=null7:i   i=6   n=6   s=null8:静态块   i=7   n=99   s=smain9:j   i=8   n=100   s=s10:构造快   i=9   n=101   s=s11: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 默认构造函数被调用

可以看到,继承情况下先初始化父类静态,然后子类静态,然后父类成员变量,父类构造函数,然后是子类成员变量跟构造函数。

0 0