Java类的初始化

Java提供了两种不同的初始化类型,各自是类的初始化和对象的初始化。

类成员都是静态的,默认会设置一个值。对象的初始化会在构造函数里面进行。但假设想要赋给静态变量非默认值。或者是初始化一类共同拥有的对象属性(不论调用哪个构造函数)。那么就须要一些特殊的方法。提供了静态初始化块和非静态初始化块来处理这两种情况.

  1. 静态初始化块

静态初始化块是通过static{}来定义的。一个简单的代码示比例如以下:

public class CorderStatic {
staticint idx;

static{
    System.out.println("idx: " + Integer.toString(idx++));
    System.out.println("idx: " + Integer.toString(idx));
}

publicstatic void main(String[] argv) {
    System.out.println("DONE");
}
}
代码执行的结果是:

idx: 0

idx: 1

DONE

从输出结果能够看出静态初始化块在静态成员的初始化后调用。并且假设类中存在多个静态初始化块。则依据出现的次序进行调用。

  1. 非静态初始化块

非静态初始化块定义在{}块中。其与静态初始化块的差别是没有statickeyword修辞。

測试代码例如以下:

public class CorderInstance {
    int idx;

{
    System.out.println("idx: " + Integer.toString(idx++));
    System.out.println("idx: " + Integer.toString(idx++));
}

publicCorderInstance() {
    System.out.println("idxin constructor : " + Integer.toString(idx));
}

public static void main(String[] argv) {
    newCorderInstance();

    System.out.println("DONE");
}
}

代码输出例如以下:

idx: 0

idx: 1

idxin constructor : 2

DONE

可见,非静态初始化块在对象属性初始化结束。构造函数调用前被调用。

  1. 初始化顺序

假设一个类里面定义了静态和非静态的初始化块。哪个会先被运行呢?測试代码例如以下:

public class Corder {
static int staticpro;

static{
    System.out.println("staticblock : " + Integer.toString(staticpro));
}

int instancepro;

{
    System.out.println("non-staticblock." + Integer.toString(instancepro++));
}

publicCorder() {
    System.out.println("instanceproperty : " + Integer.toString(instancepro++));
    System.out.println("Theconstructor had been complete.");
}

publicstatic void main(String[] argv) {
    newCorder();
}
}


代码输出例如以下:

staticblock : 0

non-staticblock.0

instanceproperty : 1

Theconstructor had been complete.

可见,静态初始化块会先被调用。然后是非静态初始化块,最后是构造函数。

  1. 继承与初始化

初始化块在遇到类继承时。情况要变得复杂一些。

先把測试代码贴出来:

public class CorderInherit {
static int staticpro;
staticA a;

static{
    System.out.println("staticinitialization : " + Integer.toString(staticpro));

    if(a == null) {
        System.out.println("classa is null.");
    }

    a= new B(10);
}

intinstancepro;
A aa;

{
    instancepro= 10;
    System.out.println("specialblock." + Integer.toString(instancepro));
    aa= new B(10);
}

publicCorderInherit(int i) {
    System.out.println("instanceproperty : " + Integer.toString(instancepro));
    instancepro= i;

    System.out.println("staticproperty : " + Integer.toString(staticpro));
    System.out.println("instanceproperty : " + Integer.toString(instancepro));

    System.out.println("Theconstructor had been complete.");
}

    publicstatic void main(String[] argv) {
        newCorderInherit(-1);
    }
}

class A {
    static int index;

    static{
        System.out.println("ClassA static 1 " + Integer.toString(index++));
    }

    {
        System.out.println("ClassA special 1 " + Integer.toString(index++));
    }

    public A() {
        System.out.println("constructclass A." + Integer.toString(index++));
    }

    static{
        System.out.println("classA static 2 " + Integer.toString(index++));
    }

    {
        System.out.println("ClassA Special 2 " + Integer.toString(index++));
    }
}

class B extends A {
     static int index;

     static{
         System.out.println("ClassB static 1 " + Integer.toString(index++));
     }

     {
         System.out.println("ClassB special 1 " + Integer.toString(index++));
     }

     public B(int i) {
         System.out.println("constructclass B." + Integer.toString(index++));
     }

     static{
         System.out.println("classB static 2 " + Integer.toString(index++));
     }

     {
         System.out.println("ClassB Special 2 " + Integer.toString(index++));
      }
}


代码输出例如以下:

staticinitialization : 0

classa is null.

ClassA static 1 0

classA static 2 1

ClassB static 1 0

classB static 2 1

ClassA special 1 2

ClassA Special 2 3

constructclass A.4

ClassB special 1 2

ClassB Special 2 3

constructclass B.4

specialblock.10

ClassA special 1 5

ClassA Special 2 6

constructclass A.7

ClassB special 1 5

ClassB Special 2 6

constructclass B.7

instanceproperty : 10

staticproperty : 0

instanceproperty : -1

Theconstructor had been complete.

观察上面的输出,能够看出,当实例化B的对象时,虚拟机会载入B.class。但由于B继承A。所以A.class也会被载入。这就导致AB的静态初始化块被分别调用。

构造B的对象时,A的非静态初始化块和默认构造函数都会被调用,然后才是B的非静态初始化块和构造函数。

  1. 结论

通过上面的样例能够看出,类的完整初始化顺序例如以下(子类为当前类,或者要new的类):

  1. 给父类的静态成员赋默认值

  2. 按出现顺序调用父类的静态初始化块

  3. 给子类的静态成员赋默认值

  4. 按出现顺序调用子类的静态初始化块

  5. 赋给父类对象属性默认值

  6. 按顺序调用父类对象的非静态初始化块

  7. 调用父类构造函数

  8. 赋给子类对象属性默认值

  9. 按顺序调用子类对象的非静态初始化块

  10. 调用子类构造函数

原文地址:https://www.cnblogs.com/lcchuguo/p/5378720.html