如何加载Class文件到JVM
如下图所示,是ClassLoader加载一个class文件到JVM时需要经过的步骤:
第一阶段是找到.class文件并把这个文件包含的字节码加载到内存中。 第二阶段又可以分为三个步骤,分别是字节码验证、Class类数据结构分析及相应的内存分配和最后的符号表的链接。 第三阶段是类中静态属性和初始化赋值,以及静态块的执行。
加载字节码到内存
其实在抽象类ClassLoader中并没有定义如何去加载,如何去找到指定类并且把它的字节码加载到内存需要在子类中去实现,也就是要实现findClass()
方法。看下在URLClassLoader中如何实现findeClass的,在URLClassLoader中通过一个URLClassPath类帮助取得要加载的class文件字节流,而这个URLClassPath定义了到哪里去找这个class文件,如果找到了这个class文件,再读取它的byte字节流,然后通过调用defineClass方法来创建类对象。
源码如下:
protected Class<?> findClass(final String name)
throws ClassNotFoundException
{
final Class<?> result;
try {
result = AccessController.doPrivileged(
new PrivilegedExceptionAction<Class<?>>() {
public Class<?> run() throws ClassNotFoundException {
String path = name.replace('.', '/').concat(".class");
Resource res = ucp.getResource(path, false);
if (res != null) {
try {
return defineClass(name, res);
} catch (IOException e) {
throw new ClassNotFoundException(name, e);
}
} else {
return null;
}
}
}, acc);
} catch (java.security.PrivilegedActionException pae) {
throw (ClassNotFoundException) pae.getException();
}
if (result == null) {
throw new ClassNotFoundException(name);
}
return result;
}
我们再来看一下URLClassLoader类的构造函数,我们发现,必须要指定一个URL数据才能够创建URLClassLoader对象,也就是必须要指定这个ClassLoader默认到哪个目录下去查找class文件。
public URLClassLoader(URL[] urls) {
super();
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkCreateClassLoader();
}
ucp = new URLClassPath(urls);
this.acc = AccessController.getContext();
}
这个URL数组也是创建URLClassPath对象的必要条件。从URLClassPath的名字中就可以发现它是通过URL的形式来表示ClassPath路径的。 在 创建URLClassPath对象时,会根据传过来的URL数据中的路径来判断时文件还是jar包,根据路径的不同分别创建FileLoader或者JarLoader,或者使用默认的加载器。当JVM调用findeClass时这几个加载器来将class文件的字节码加载到内存中。 如何设置每个ClassLoader的搜索路径呢? 下表是BootStrap ClassLoader、ExtClassLoader和AppClassLoader的参数形式
classLoader类型 |
参数选项 |
说明 |
---|---|---|
BootStrap ClassLoader |
-Xbootclasspath: |
设置BootStrap ClassLoader的搜索路径 |
ExtClassLoader |
-Xbootclasspath/a: -Xbootclasspath/p: |
把路径添加到已存在BootStrap ClassLoader搜索路径的后面(a)和前面(p) |
AppClassLoader |
-Djava.ext.dirs |
设置AppClassLoader的搜索路径 |
AppClassLoader |
-Djava.class.path= -cp或-classpath |
设置AppClassLoader的搜索路径 |
在上面的参数设置中,最常用到的就是设置classpath 的环境变量,因为通常都是让Java运行指定的程序。如果在通过命令执行一个类时出现NoClassDefFoundError错误,那么很可能是没有指定classpaht所致,或者指定了classpath但是没有指明包名。
验证与解析
- 字节码验证,类装入器对于类的字节码要做许多检测,以确保格式正确、行为正确。
- 类准备,在这个阶段准备代表每个类中定义的字段、方法和实现接口所必需的数据结构。
- 解析,在这个阶段,类装入器装入类所引用的其他所有类。可以用许多方式引用类,如超类、接口、字段、方法签名、方法中使用的本地变量。
初始化class对象
在类中包含的静态初始化器都被执行,在这一阶段末尾静态字段被初始化为默认值。
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 【每周一库】- cached - 缓存结构型、辅助函数记忆化
- meta生成器 —— 表单元素组件 meta表单代码meta的模板data变幻
- 不用写代码也能做表单 —— 加载meta即可 菜单表单加载json运行效果。ModelAbout
- 从0到1,手把手教你入门 etcd
- 数据结构:手把手带你了解 ”图“ 所有知识!(含DFS、BFS)
- 设计模式之单例模式
- AndroidStudio创建JNI 工程与调用
- Java 版植物大战僵尸思路和源码分享!
- 你好MyBatis 入门篇
- 你好MyBatis 中级篇
- 你好MyBatis 中高级篇
- Nginx反代理获取真实IP
- 你好MyBatis 高级篇
- redis实现分布式锁:他说,他的分布式锁,很润哦
- Python_字符串