java 类初始化,实例化顺序

记得在学校初学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 默认构造函数被调用

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值