Java类的初始化

大家都知道类的初始化顺序,有父类的时候,顺序是:

–> 父类的静态成员(包括静态变量和静态代码块)
–> 子类的静态成员(包括静态变量和静态代码块)
–> 父类的普通成员(普通成员变量和普通代码块)和构造函数
–> 子类的普通成员(普通成员变量和普通代码块)和构造函数

我个人觉得大家平时说的初始化可以分成两类,也即两个阶段,首先是类的初始化,其次是对象的初始化。静态成员初始化属于类初始化,普通成员和构造函数初始化属于对象初始化。

原因如下示例:

class H {
    static int s = 1;
    static {
        System.out.println("first static block");
        System.out.println("ordinary var s initial: " + s);
        s = 2;
        System.out.println("ordinary var s afer change: " + s);
    }
    public int a;
    {
        System.out.println("first ordinary block");
        System.out.println("ordinary var a : " + a);
    }

    static {
        System.out.println("last static block " + s);
    }

    public H() {
        System.out.println("constructor");
    }

    {
        System.out.println("last ordinary block");
    }
}

在main函数里

new H();
new H();

则运行结果如下

//静态成员
first static block
ordinary var s initial: 1
ordinary var s afer change: 2
last static block 2
//普通成员
first ordinary block
ordinary var a : 0
last ordinary block
//构造函数
constructor
//普通成员
first ordinary block
ordinary var a : 0
last ordinary block
//构造函数
constructor

代码就不细讲了,很明显可以看到,在两次创建对象的过程中,静态成员初始化了一次,对象成员(姑且这么叫先)初始化两次。当然,类静态变量存放在方法区,实例变量存在于类对象对应的堆内存中,每创建一个对象就在堆内存开辟一个内存区域存放对象成员等内容,所以也就很明白了。


我要说的是另外一个值得注意的地方,就是Class.forName(String name)方法。Class.forName()方法返回的是一个类(Class对象),作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段。

在main函数里调用该方法

try {
        Class.forName("H");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

则运行结果如下

//静态成员
first static block
ordinary var s initial: 1
ordinary var s afer change: 2
last static block 2

只有类静态成员初始化了。
JDK文档里是这样说的:

A call to forName("X") causes the class named X to be initialized.

另外,还有一个类加载方法forName(String name, boolean initialize, ClassLoader loader),根据参数名称就可以理解参数的含义,其中第二项参数就是确定是否需要初始化类。

那么在其他函数里这样调用(因为有this关键字不能在静态的main方法里用):

try {
    //initialize = false
    Class.forName("H",false,this.getClass().getClassLoader());  
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

运行后什么也没有显示,即没有进行类的初始化工作,但是没有抛异常,说明类已经加载完成了,估计连接也已经完成。

再测试如下,创建实例对象:

try {
    Class c = Class.forName("H",false,this.getClass().getClassLoader());
    c.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
    e.printStackTrace();
}

则运行结果如下

//静态成员
first static block
ordinary var s initial: 1
ordinary var s afer change: 2
last static block 2
//普通成员
first ordinary block
ordinary var a : 0
last ordinary block
//构造函数
constructor

new H(); 是一样的效果。


参考
Class.forName
Java初始化顺序

你可能感兴趣的:(java基础)