链接 将Java类的二进制代码合并到JVM的运行状态之中的过程 •
•验证:
– 确保加载的类信息符合JVM规范,没有安全方面的问题。
• 准备:
– 正式为类变量(static变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配
• 解析
– 虚拟机常量池内的符号引用替换为直接引用的过程
初始化 •
• 初始化阶段是执行类构造器()方法的过程。类构造器()方法是由编译器自动收集 类中的所有类变量的赋值动作和静态语句块(static块)中的语句合并产生的。
• 当初始化一个类的时候,如果发现其父类还没有进行过初始化、则需要先出发其父类的初始化
• 虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步。
package com.lzy.JVM;
public class Demo01 {
public static void main(String[] args) {
A a=new A();
System.out.println(A.width);
A a2=new A();//类加载和初始化只有一次
}
}
class A extends A_Father{
public static int width=100;
static {
System.out.println("静态初始化类A");
width=300;
}
public A() {
System.out.println("创建A类的对象");
}
}
class A_Father{
static {
System.out.println("静态初始化A_Father");
}
}
运行结果
静态初始化A_Father
静态初始化类A
创建A类的对象
300
分析:
创建A类的对象
运行以下代码时
A a=new A();
System.out.println(A.width);
运行结果:
静态初始化A_Father
静态初始化类A
创建A类的对象
300
说明,虽然创建A类对象,但它会先初始化父类。然后初始化自己,最后才打印结果
运行以下代码时:
A a2=new A();
运行结果:
创建A类的对象
不在初始化父类和自己,说明类的加载和初始化只有那么一次
什么时候会发生类的初始化?甚么时候不会发生类的初始化?
• 类的主动引用(一定会发生类的初始化)
– new一个类的对象
– 调用类的静态成员(除了final常量)和静态方法
– 使用java.lang.reflect包的方法对类进行反射调用
– 当虚拟机启动,java Hello,则一定会初始化Hello类。说白了就是先启动main方法所在的类
– 当初始化一个类,如果其父类没有被初始化,则先会初始化他的父类
• 类的被动引用(不会发生类的初始化)
– 当访问一个静态域时,只有真正声明这个域的类才会被初始化
• 通过子类引用父类的静态变量,不会导致子类初始化
– 通过数组定义类引用,不会触发此类的初始化
– 引用常量不会触发此类的初始化(常量在编译阶段就存入调用类的常量池中了)
例:
package com.lzy.JVM;
public class Demo01 {
public static void main(String[] args) throws ClassNotFoundException {
//主动引用
//new A();//new一个类的对象,会初始化
//System.out.println(A.width);//调用类的静态成员,会初始化
//Class.forName("com.lzy.JVM.A");// 使用java.lang.reflect包的方法对类进行反射调用 ,会初始化
//被动引用
//System.out.println(A.SMALL);//调用final常量,不会初始化,(用final修饰的为常量,对应类的被动引用第三条:引用常量不会触发此类的初始化(常量在编译阶段就存入调用类的常量池中了))
//A[]as=new A[10];
System.out.println(B.width);//当访问一个静态域时,只有真正声明这个域的类才会被初始化
//通过子类访问父类静态域时,子类并不会被初始化,但父类会初始化
}
}
class B extends A{
static {
System.out.println("静态初始化B");
}
}
class A extends A_Father{
public static int width=100;
public static final int SMALL=0;
static {
System.out.println("静态初始化类A");
width=300;
}
public A() {
System.out.println("创建A类的对象");
}
}
class A_Father{
static {
System.out.println("静态初始化A_Father");
}
}
本文深入探讨Java虚拟机(JVM)中类加载的过程,包括链接、验证、准备、解析和初始化等关键步骤,并通过实例代码展示类的主动引用与被动引用的区别。
3151

被折叠的 条评论
为什么被折叠?



