大家都知道类的初始化顺序,有父类的时候,顺序是:
–> 父类的静态成员(包括静态变量和静态代码块)
–> 子类的静态成员(包括静态变量和静态代码块)
–> 父类的普通成员(普通成员变量和普通代码块)和构造函数
–> 子类的普通成员(普通成员变量和普通代码块)和构造函数
我个人觉得大家平时说的初始化可以分成两类,也即两个阶段,首先是类的初始化,其次是对象的初始化。静态成员初始化属于类初始化,普通成员和构造函数初始化属于对象初始化。
原因如下示例:
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();
是一样的效果。