您的位置:首页 > 编程语言 > Java开发

Java 类加载时机和顺序

2016-09-09 10:51 246 查看

Java类加载时机

什么情况下需要开始类加载过程的第一个阶段:”加载”。虚拟机规范中并没强行约束,这点可以交给虚拟机的的具体实现自由把握,但是对于初始化阶段虚拟机规范是严格规定了如下几种情况,如果类未初始化会对类进行初始化。

创建类的实例

访问类的静态变量 (除常量【 被final修辞的静态变量】 原因:常量一种特殊的变量,因为编译器把他们当作值(value)而不是域(field)来对待。如果你的代码中用到了常变量(constant variable),编译器并不会生成字节码来从对象中载入域的值,而是直接把这个值插入到字节码中。这是一种很有用的优化,但是如果你需要改变final域的值那么每一块用到那个域的代码都需要重新编译。

访问类的静态方法

反射 如( Class.forName(“my.xyz.Test”) )

当初始化一个类时,发现其父类还未初始化,则先出发父类的初始化

虚拟机启动时,定义了main()方法的那个类先初始化

以上情况称为称对一个类进行 “主动引用” ,除此种情况之外,均不会触发类的初始化,称为 “被动引用”

被动引用例子

子类调用父类的静态变量,子类不会被初始化。只有父类被初始化。 对于静态字段,只有直接定义这个字段的类才会被初始化.

通过数组定义来引用类,不会触发类的初始化

访问类的常量,不会初始化类

类装载(静态代码执行只在这阶段顺序进行,而且只有一次)

如果只调用类的静态方法,只要加载了某个类,他的静态方法就产生了,不需要实例化。

在new B一个实例时首先要进行类的装载。(类只有在使用New调用创建的时候才会被java类装载器装入)

在装载类时,先装载父类A,再装载子类B

装载父类A后,完成静态动作(包括静态代码和变量,它们的级别是相同的,安装代码中出现的顺序初始化)

装载子类B后,完成静态动作

其他操作

链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的;

校验:检查导入类或接口的二进制数据的正确性;

准备:给类的静态变量分配并初始化存储空间;

解析:将符号引用转成直接引用;

加载操作完成,开始进行实例化

在实例化子类B时,先要实例化父类A

实例化父类A时,先成员实例化(非静态代码)

父类A的构造方法

子类B的成员实例化(非静态代码)

子类B的构造方法

先初始化父类的静态代码—>初始化子类的静态代码–>初始化父类的非静态代码—>初始化父类构造函数—>初始化子类非静态代码—>初始化子类构造函数

class SingleTon {
private static SingleTon singleTon = new SingleTon();
// count1=1,count2=1
public static int count1;
// count1=1,count2=1(没进行初始化)
public static int count2 = 0;
// count1=1,count2=0

private SingleTon() {
count1++;
count2++;
}

public static SingleTon getInstance() {
return singleTon;
}
}

public class Test {
public static void main(String[] args) {
SingleTon singleTon = SingleTon.getInstance();
System.out.println("count1=" + singleTon.count1);
System.out.println("count2=" + singleTon.count2);
}
}


SingleTon singleTon = SingleTon.getInstance();调用了类的SingleTon调用了类的静态方法,触发类的初始化

类加载的时候在准备过程中为类的静态变量分配内存并初始化默认值 singleton=null count1=0,count2=0

类初始化化,为类的静态变量赋值和执行静态代码快。singleton赋值为new SingleTon()调用类的构造方法

调用类的构造方法后count=1;count2=1

继续为count1与count2赋值,此时count1没有赋值操作,所有count1为1,但是count2执行赋值操作就变为0
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: