一、类加载过程(初始化)
Loading
-
类加载采用双亲委派机制(主要出于安全来考虑)
-
类加载器说明
-
LazyLoading 五种情况
- new getstatic putstatic invokestatic指令,访问final变量除外
- java.lang.reflect对类进行反射调用时
- 初始化子类的时候,父类首先初始化
- 虚拟机启动时,被执行的主类必须初始化
- 动态语言支持java.lang.invoke.MethodHandle解析的结果为REF_getstatic REF_putstatic REF_invokestatic的方法句柄时,该类必须初始化
Linking
-
Verification
验证文件是否符合JVM规定
-
Preparation
静态成员变量赋默认值
-
Resolution
将类、方法、属性等符号引用解析为直接引用
常量池中的各种符号引用解析为指针、偏移量等内存地址的直接引用
Initializing
- 调用类初始化代码 ,给静态成员变量赋初始值
加载过程示意图
二、ClassLoader相关知识
LoadClass过程
1、从类加载器的缓存中查找是否加载过(找到返回结果,未找到递归从父加载器查找)
2、类加载器中未找到,调用findClass加载Class文件
3、加载上,返回,加载不上,返回ClassNotFound异常
自定义类加载器
- extends ClassLoader
- 重写 findClass() ,返回defineClass(byte数组转换成class)
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try{
File f = new File("类文件路径",name.replaceAll(".","/"));
FileInputStream fis = new FileInputStream(f);
ByteArrayOutputStream bt = new ByteArrayOutputStream();
int b = 0;
while((b = fis.read()) != 0){
bt.write(b);
}
byte[] bytes = bt.toByteArray();
return defineClass(name,bytes,0,bytes.length);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) throws Exception{
T03_CustomerClassloader cus = new T03_CustomerClassloader();
Class clazz = cus.loadClass("包名");
Hello h = (Hello) clazz.newInstance();
h.m();
}
如何打破双亲委派
- 重写loadClass()方法
- 何时打破过?
JDK1.2之前,自定义ClassLoader都必须重写loadClass()
ThreadContextClassLoader可以实现基础类调用实现类代码,通过thread.setContextClassLoader指定
应用场景
热启动,热部署