java类加载的全过程
类的加载和初始化只有一次
全过程一共分为了七个阶段:
1, 加载 2,验证 3,准备 4,解析 5,初始化 6,使用 7,卸载
其中 234 蓝色字体又可以认为是 链接的过程 这样看来 我们主要就关注 加载 链接和初始化的过程了
******************
加载
将class字节码加载到内存中去,并将这些静态数据 转换成方法区(一种特殊的堆)中数据结构, 同时对应在堆中 生成一个java.lang.class 对象,作为方法区中的数据的入口;
这个过程需要类加载参与;
链接
2,验证 确保加载的类的信息符合JVM的规范,没有安全方面的问题
3,准备 正式为类变量分配内存和初始化赋值(比如int的初始值 赋值为0)的操作,这些内存将都在方法去进行分配
4,解析 虚拟机常量池内 的 符号引用 替换为直接引用;
package annotation;
/**
* 1, 最先初始化静态域
* 2, 其次 执行构造器
* 3, 然后打印 a的属性
* 静态变量(静态域)和静态初始化块被整合成了一块去执行
* **/
public class TestClassLoad {
public static void main(String[] args) {
// TODO Auto-generated method stub
A a= new A();
System.out.println(a.width);
}
}
class A{
static int width;
{
System.out.println("初始化静态域");
width =3000;
}
public A() {
// TODO Auto-generated constructor stub
System.out.println("构建A");
}
}
初始化
。初始化是执行类构造器(这个我们直接接触不到)的class intit(clinit)方法的操作,这个方法 是编译器收集了类中的 所有类变量的赋值操作 和 静态语句块的操作合并产生的; 也就是说 除了静态 语句块中的操作会最开始执行;
。虚拟机保证一个类 在各种多线程环境下 线程是安全的 。
****************
类的主动引用(会触发初始化)
1,new 一个对象;
2,调用类的静态成员和静态方法(final除外)
3,使用 java.lang.reflect 的方法对类进行发射调用
4,当虚拟机启动 一定会触发,说白了就是main方法所在的类一定会触发加载
5,当初始化一个类,父类没有初始化,那么先初始化父类
类的被动引用(不会触发初始化)
1,当访问一个类的静态域时,只有真正声明了这个静态域的类才会被初始化(实际上都没有初始化感觉)
package annotation;
/**
* 当访问一个类的静态域时,只有真正声明了这个静态域的类才会被初始化
* B作为A的子类, 调用B的继承过来静态属性,不会初始化B,只会初始化属性的实际声明者A
* 实际上都没有初始化
* **/
public class TestClassLoad {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(B.width);
}
}
class B extends A{
static {
System.out.println("初始化静态域B");
}
}
class A{
public static int width=100;
public static final int max=10;
{
System.out.println("初始化静态域A");
}
public A() {
// TODO Auto-generated constructor stub
System.out.println("构建A");
}
}
2,通过数组 定义类引用 ,不会触发此类初始化
package annotation;
/**
* 通过数组 定义类引用 ,不会触发此类初始化
* **/
public class TestClassLoad {
public static void main(String[] args) {
// TODO Auto-generated method stub
A [] a=new A[10];
}
}
class A{
static int width;
{
System.out.println("初始化静态域");
width =3000;
}
public A() {
// TODO Auto-generated constructor stub
System.out.println("构建A");
}
}
3,引用常量 的变量不会引起初始化(在编译阶段 此类就在调用类的常量池中了);同 (调用类的静态成员和静态方法(final))
package annotation;
/**
* 引用常量 的变量不会引起初始化(在编译阶段 此类就在调用类的常量池中了);同 (调用类的静态成员和静态方法(final)
* **/
public class TestClassLoad {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(A.max);
}
}
class A{
static int width;
public static final int max=10;
{
System.out.println("初始化静态域");
width =3000;
}
public A() {
// TODO Auto-generated constructor stub
System.out.println("构建A");
}
}
上一篇: java.lang.IllegalArgumentException: String length must be a multiple of four.
下一篇: MQTT协议 -- 消息报文格式
推荐阅读
-
Laravel 加载第三方类库的方法
-
java处理字节的常用工具类
-
java分页工具类的使用方法
-
Java日期时间API系列5-----Jdk7及以前的日期时间类TimeUnit在并发编程中的应用
-
Java日期时间API系列12-----Jdk8中java.time包中的新的日期时间API类,日期格式化,常用日期格式大全
-
Java中Date()类 日期转字符串、字符串转日期的问题
-
java类成员默认的可访问性是什么?你猜
-
Java类加载机制详解
-
Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析
-
java包装类和值类型的关系