Java类加载机制
2018-03-27 13:13
204 查看
上文我们说到了JVM的内存模型,本文我们进一步的介绍JVM的类加载机制,先上一张很经典的图:
由该图,我们开始展开探讨。上图将类加载的步骤分为七步,加载,验证,准备,解析,初始化,使用,卸载。
一、加载
加载的核心目的是为了将类信息读到内存中,Java中提供一个java.lang.ClassLoader的loadClass()方法,具体步骤一共细分为如下几步:
1.通过全类名获取字节码文件
2.将改字节码存储的内容转化为方法区中类的数据结构
3.在内存中生成一个Class对象,作为访问方法区数据的入口
二、验证
验证是连接的第一步,他的主要作用是用于检查二进制文件的合法性,只有当他符合JVM的要求才有效,否则可能会造成当前虚拟机的安全危害。
三、准备
是一个给类的静态变量在方法区分配内存并赋初始值阶段(非static修饰过的变量是在堆中分配空间,是在对象被实例化才开始分配),如:
public static int value=123; 在准备阶段,它的值是0,只有到初始化阶段,他才会被赋值123。
四、解析
将常量池中的符号引用替换为直接引用的过程。(未理解)
五、初始化
为类加载连接的最后一步。当这个阶段,才开始执行Java代码,执行静态代码块,设置静态变量的值为程序员的预定值。
一下情况下会初始化类:
new一个对象时(仅仅定义是不会初始化的);
读取类的静态变量以及静态方法时;
使用反射调用未被初始化的类时;(这个并无特别解释,只是在验证时发现,获取只有通过Class.forName()获取Class对象时,才会初始化,通过类名.class,并不会初始化,即使调用了Class对象中的方法)
初始化一个类时,会初始化他的父类;
JVM启动时,main方法的那个类;
类初始化时,有父类的子类的初始化顺序:
1、按照出现顺序,会依次初始化父类静态变量和静态代码块;
2、再按照出现顺序,依次初始化子类的静态变量和静态代码块;
3、初始化父类的普通变量以及构造方法;
4、初始化子类的普通变量和构造方法;
补充一个很经典的类加载例子:
public class SuperClass {
static{
System.out.println("SuperClass init!");
}
public static int value=123;
}
public class SubClass extends SuperClass {
static{
System.out.println("SubClass init!");
}
}
public class NotInitialization {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(SubClass.value);
}
} 以上代码的执行结果为:
SuperClass init!
123
由此得出结论,通过子类调用父类的静态变量,只会初始化父类,并不会初始化子类。对于静态字段来说,只有直接定义静态字段的那个类会被初始化。
由该图,我们开始展开探讨。上图将类加载的步骤分为七步,加载,验证,准备,解析,初始化,使用,卸载。
一、加载
加载的核心目的是为了将类信息读到内存中,Java中提供一个java.lang.ClassLoader的loadClass()方法,具体步骤一共细分为如下几步:
1.通过全类名获取字节码文件
2.将改字节码存储的内容转化为方法区中类的数据结构
3.在内存中生成一个Class对象,作为访问方法区数据的入口
二、验证
验证是连接的第一步,他的主要作用是用于检查二进制文件的合法性,只有当他符合JVM的要求才有效,否则可能会造成当前虚拟机的安全危害。
三、准备
是一个给类的静态变量在方法区分配内存并赋初始值阶段(非static修饰过的变量是在堆中分配空间,是在对象被实例化才开始分配),如:
public static int value=123; 在准备阶段,它的值是0,只有到初始化阶段,他才会被赋值123。
四、解析
将常量池中的符号引用替换为直接引用的过程。(未理解)
五、初始化
为类加载连接的最后一步。当这个阶段,才开始执行Java代码,执行静态代码块,设置静态变量的值为程序员的预定值。
一下情况下会初始化类:
new一个对象时(仅仅定义是不会初始化的);
读取类的静态变量以及静态方法时;
使用反射调用未被初始化的类时;(这个并无特别解释,只是在验证时发现,获取只有通过Class.forName()获取Class对象时,才会初始化,通过类名.class,并不会初始化,即使调用了Class对象中的方法)
初始化一个类时,会初始化他的父类;
JVM启动时,main方法的那个类;
类初始化时,有父类的子类的初始化顺序:
1、按照出现顺序,会依次初始化父类静态变量和静态代码块;
2、再按照出现顺序,依次初始化子类的静态变量和静态代码块;
3、初始化父类的普通变量以及构造方法;
4、初始化子类的普通变量和构造方法;
补充一个很经典的类加载例子:
public class SuperClass {
static{
System.out.println("SuperClass init!");
}
public static int value=123;
}
public class SubClass extends SuperClass {
static{
System.out.println("SubClass init!");
}
}
public class NotInitialization {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(SubClass.value);
}
} 以上代码的执行结果为:
SuperClass init!
123
由此得出结论,通过子类调用父类的静态变量,只会初始化父类,并不会初始化子类。对于静态字段来说,只有直接定义静态字段的那个类会被初始化。
相关文章推荐
- 关于Java类加载双亲委派机制的思考(附一道面试题)
- Java类加载机制深度分析
- 深入研究Java类加载机制
- Java类加载机制详解
- Tomcat类加载机制和JAVA类加载机制的比较
- Java类加载机制(初始化顺序)
- java类加载机制
- Java类加载机制
- java类加载机制
- java类加载机制
- JVM研究(一)Java类加载机制
- Java类加载机制 - static关键字
- Java类加载机制
- Java类加载机制浅析
- 剑指Offer——知识点储备-故障检测、性能调优与Java类加载机制
- Java类加载机制
- Java类加载机制
- java类加载机制
- Java虚拟机13:Java类加载机制
- java类的加载机制