zoukankan      html  css  js  c++  java
  • 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. 调用子类构造函数

  • 相关阅读:
    SQL分类
    广度/深度优先生成树
    图的基本概念
    哈夫曼树构造/哈夫曼编码
    二叉排序树/平衡二叉树
    树、森林与二叉树的转换
    树/二叉树的基本性质
    /*传说中的土办法找中序前驱*/
    KiCAD原理图更换库
    博客园添加版权信息
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/5378720.html
Copyright © 2011-2022 走看看