Java类加载机制
Java程序在运行前需要先编译成class文件
,Java类初始化的时候会调用java.lang.ClassLoader
加载类字节码,ClassLoader
会调用JVM的native方法(defineClass0/1/2
)来定义一个java.lang.Class
实例。
class文件
Java字节码类文件(.class)是Java编译器编译Java源文件(.java)产生的“目标文件”。它是一种8位字节的二进制流文件。
Java类加载机制
主要作用:Java类文件的加载进内存
Bootstrap ClassLoader(引导类加载器)
Extension ClassLoader(扩展类加载器)
App ClassLoader(系统类加载器)—默认的类加载器
ClassLoader.getSystemClassLoader()
返回的系统类加载器也是AppClassLoader,见示例。
1 |
|
通过引导类加载器加载(该类加载器实现于JVM层,采用C++编写),获取一个类的类加载器时候会返回一个
null
值,如loader3
java.io.File
类同理间loader4
双亲委派
一个java类加载进JVM内存的过程
- 每个类加载器对他加载过的类都有缓存
- 向上委托查找,向下委托加载
JDK的类加载对象
1 | ClassLoader -> SecureClassLoader -> URLClassLoader -> ExtClassLoader,AppClassLoader |
ClassLoader类
抽象类,主要功能:通过指定的类名称,找到或生成对应的字节码,返回java.lang.Class
类的实例。
ClassLoader
类有如下和加载类相关的方法:
方法 | 说明 |
---|---|
getParent() |
返回该类加载器的父类加载器 |
loadClass(String name) |
加载指定的Java类 |
findClass(String name) |
查找指定的Java类 |
findLoadedClass(String name) |
查找JVM已经加载过的类 |
defineClass(String name,byte[] b,int off,int len) |
字节数组b转成Java类 |
resolveClass |
链接指定的Java类 |
ClassLoader作用
根据文件地址获取输入流
1 | ClassLoader loader = this.getClass().getClassLoader(); |
Java类动态加载机制
显式:通常使用Java反射
或者ClassLoader
来动态加载一个类对象。
隐式:类名.方法名()
或new
类实例
常用的类动态加载方式:
1 | //默认会初始化被加载类的静态属性和方法 |
自定义ClassLoader
- 继承一个系统类加载器。
- 覆盖父类的findClass方法。
- 在方法中,调用defineClass方法在JVM内存中定义一个类。
自己的类加载器来实现加载自定义的字节码
1 | package com.drop.test; |
类加载隔离
1 | package com.drop.test; |
动态加载字节码的几种方法
URLClassLoader
java.lang.ClassLoader
是所有的类加载器的父类,java.lang.ClassLoader
有非常多的子类加载器,比如我们用于加载jar包的java.net.URLClassLoader
其本身通过继承java.lang.ClassLoader
类,重写了findClass
方法从而实现了加载目录class文件甚至是远程资源文件。
1 | //Hello.java |
构造恶意类
static方法
在没有创建对象的情况下来进行调用(方法/变量)
1 | import java.io.IOException; |
远程调用
1 | public class TestURLClassLoader { |