虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换、解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。Java类的加载、连接和初始化都是在程序运行期间完成的,也就是动态加载和动态连接的。
# 类加载的时机
![](https://img.kancloud.cn/72/1c/721c99a683916644e86d1ab6b3c6449f_487x162.png)
加载、验证、准备、初始化、卸载这5个阶段的顺序是确定的,解析则不一定,有时可以在初始化之后再开始。
Java虚拟机并没有规定什么时候一定要开始第一个阶段“加载”,但规定了有且仅有下面5中情况一定要进行“初始化”:
1、遇到new、getstatic、putstatic、invokestatic四个字节码指令时,生成这几个指令最常见的场景:new关键字实例化对象时、读取或设置一个类的静态字段时、调用一个类的静态方法时。
2、使用java.lang.reflect包的方法对类进行反射调用时,如果类没有进行过初始化,需要触发初始化
3、初始化一个类时,如果发现其父类还没初始化,需要先触发其父类的初始化
4、虚拟机启动时,需要指定一个要执行的主类(包含main方法的那个类),虚拟机会先初始化这个主类
5、使用JDK1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后解析的结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,且这个方法句柄对应的类没有进行过初始化,需要先触发其初始化
上面5中情况中的行为称为对一个类进行主动引用,除此之外其他引用类的方式不会触发类的初始化,称为被动引用。
# 类加载的过程
## 加载
## 验证
## 准备
## 解析
## 初始化
# 类加载调用顺序
以下面示例进行测试:
```java
/**
* 控制台打印
*/
class Log {
public static String baseFieldInit() {
System.out.println("Base Normal Field");
return "";
}
public static String baseStaticFieldInit() {
System.out.println("Base Static Field");
return "";
}
public static String fieldInit() {
System.out.println("Normal Field");
return "";
}
public static String staticFieldInit() {
System.out.println("Static Field");
return "";
}
}
/**
* 基类
*/
class Base {
static {
System.out.println("Base Static Block 1");
}
private static String staticValue = Log.baseStaticFieldInit();
static {
System.out.println("Base Static Block 2");
}
{
System.out.println("Base Normal Block 1");
}
private String value = Log.baseFieldInit();
{
System.out.println("Base Normal Block 2");
}
Base() {
System.out.println("Base Constructor");
}
}
/**
* 派生类
*/
class Derived extends Base {
static {
System.out.println("Static Block 1");
}
private static String staticValue = Log.staticFieldInit();
static {
System.out.println("Static Block 2");
}
{
System.out.println("Normal Block 1");
}
private String value = Log.fieldInit();
{
System.out.println("Normal Block 2");
}
Derived() {
System.out.println("Derived Constructor");
}
/**
* MAIN 主线程
*/
public static void main(String[] args) {
Derived d = new Derived();
}
}
```
打印结果如下:
```java
Base Static Block 1
Base Static Field
Base Static Block 2
Static Block 1
Static Field
Static Block 2
Base Normal Block 1
Base Normal Field
Base Normal Block 2
Base Constructor
Normal Block 1
Normal Field
Normal Block 2
Derived Constructor
```
可以看到,执行顺序如下:
1、基类静态代码块、基类静态成员变量(优先级相同,按代码出现顺序依次执行)(只有第一次加载类时执行)
2、派生类静态代码块、派生类静态成员变量(优先级相同,按代码出现顺序依次执行)(只有第一次加载类时执行)
3、基类普通代码块、基类普通成员变量(优先级相同,按代码出现顺序依次执行)
4、基类构造函数
5、派生类普通代码块、派生类普通成员变量(优先级相同,按代码出现顺序依次执行)
6、派生类构造函数
参考文档:[https://www.zhihu.com/question/49196023](https://www.zhihu.com/question/49196023)
- 导读
- Java知识
- Java基本程序设计结构
- 【基础知识】Java基础
- 【源码分析】Okio
- 【源码分析】深入理解i++和++i
- 【专题分析】JVM与GC
- 【面试清单】Java基本程序设计结构
- 对象与类
- 【基础知识】对象与类
- 【专题分析】Java类加载过程
- 【面试清单】对象与类
- 泛型
- 【基础知识】泛型
- 【面试清单】泛型
- 集合
- 【基础知识】集合
- 【源码分析】SparseArray
- 【面试清单】集合
- 多线程
- 【基础知识】多线程
- 【源码分析】ThreadPoolExecutor源码分析
- 【专题分析】volatile关键字
- 【面试清单】多线程
- Java新特性
- 【专题分析】Lambda表达式
- 【专题分析】注解
- 【面试清单】Java新特性
- Effective Java笔记
- Android知识
- Activity
- 【基础知识】Activity
- 【专题分析】运行时权限
- 【专题分析】使用Intent打开三方应用
- 【源码分析】Activity的工作过程
- 【面试清单】Activity
- 架构组件
- 【专题分析】MVC、MVP与MVVM
- 【专题分析】数据绑定
- 【面试清单】架构组件
- 界面
- 【专题分析】自定义View
- 【专题分析】ImageView的ScaleType属性
- 【专题分析】ConstraintLayout 使用
- 【专题分析】搞懂点九图
- 【专题分析】Adapter
- 【源码分析】LayoutInflater
- 【源码分析】ViewStub
- 【源码分析】View三大流程
- 【源码分析】触摸事件分发机制
- 【源码分析】按键事件分发机制
- 【源码分析】Android窗口机制
- 【面试清单】界面
- 动画和过渡
- 【基础知识】动画和过渡
- 【面试清单】动画和过渡
- 图片和图形
- 【专题分析】图片加载
- 【面试清单】图片和图形
- 后台任务
- 应用数据和文件
- 基于网络的内容
- 多线程与多进程
- 【基础知识】多线程与多进程
- 【源码分析】Handler
- 【源码分析】AsyncTask
- 【专题分析】Service
- 【源码分析】Parcelable
- 【专题分析】Binder
- 【源码分析】Messenger
- 【面试清单】多线程与多进程
- 应用优化
- 【专题分析】布局优化
- 【专题分析】绘制优化
- 【专题分析】内存优化
- 【专题分析】启动优化
- 【专题分析】电池优化
- 【专题分析】包大小优化
- 【面试清单】应用优化
- Android新特性
- 【专题分析】状态栏、ActionBar和导航栏
- 【专题分析】应用图标、通知栏适配
- 【专题分析】Android新版本重要变更
- 【专题分析】唯一标识符的最佳做法
- 开源库源码分析
- 【源码分析】BaseRecyclerViewAdapterHelper
- 【源码分析】ButterKnife
- 【源码分析】Dagger2
- 【源码分析】EventBus3(一)
- 【源码分析】EventBus3(二)
- 【源码分析】Glide
- 【源码分析】OkHttp
- 【源码分析】Retrofit
- 其他知识
- Flutter
- 原生开发与跨平台开发
- 整体归纳
- 状态及状态管理
- 零碎知识点
- 添加Flutter到现有应用
- Git知识
- Git命令
- .gitignore文件
- 设计模式
- 创建型模式
- 结构型模式
- 行为型模式
- RxJava
- 基础
- Linux知识
- 环境变量
- Linux命令
- ADB命令
- 算法
- 常见数据结构及实现
- 数组
- 排序算法
- 链表
- 二叉树
- 栈和队列
- 算法时间复杂度
- 常见算法思想
- 其他技术
- 正则表达式
- 编码格式
- HTTP与HTTPS
- 【面试清单】其他知识
- 开发归纳
- Android零碎问题
- 其他零碎问题
- 开发思路