JVM系列四:类加载
类的生命周期
加载-》验证-》准备-》解析-》初始化-》使用-》卸载

类加载过程
类加载包括以上的前五个过程:加载,验证,准备,解析,初始化
加载
1、主要完成三个工作
- 通过类的完全限定名称来定位定义该类的二进制字节流
- 将二进制字节流中的静态数据结构转化成方法区中的动态数据结构
- 在堆中生成一个代表该类的Class对象,指向方法区的数据结构,作为访问方法区的入口
2、获取二进制字节流文件的途径
- 从 ZIP 包读取,成为 JAR、EAR、WAR 格式的基础。
- 从网络中获取,最典型的应用是 Applet。
- 运行时计算生成,例如动态代理技术,在 java.lang.reflect.Proxy 使用 ProxyGenerator.generateProxyClass 的代理类的二进制字节流。
- 由其他文件生成,例如由 JSP 文件生成对应的 Class 类
验证
验证类是合理可用的
1、文件格式验证:验证Class文件格式是否符合规范和是否能够被当前版本虚拟机解释
2、元数据验证:对类的元数据进行语义验证,确保元数据没有不符合java语义规范
3、字节码验证:对类的方法体进行验证,
4、符号引用验证:验证符号引用是否能够正确解析
准备
在方法区中为类变量分配内存,并赋予系统默认初始值,指0,null这种而不是代码中手工赋予的初始值
解析
将符号应用替换成直接引用
初始化

类的初始化时机
主动引用
1、调用new、getststic,putstatic,invokestatic(读取或设置静态变量,调用静态方法)
2、通过反射实例化
3、初始化子类时,若父类还没有被初始化,则要先初始化父类
4、虚拟机启动时,加载包含Main的主类
被动引用
1、子类引用父类的静态字段,不会初始化子类
2、初始化数组类,不会初始化该类
3、常量在编译阶段就会读到常量缓冲池中,读取类的常量不会引起类的初始化
有且只有以上主动引用的四种情况才会引起类的初始化
类加载器
类加载器的定义与作用
类加载器的作用就是根据类的全限定名称获取相对应的Class二进制字节流文件,并将其加载到虚拟机内部
意义:任何一个类的唯一性是由类本身和加载该类的类加载器一起确定的
(两个类相等,包括类的 Class 对象的 equals() 方法、isAssignableFrom() 方法、isInstance() 方法的返回结果为 true,也包括使用 instanceof 关键字做对象所属关系判定结果为 true。)
分类
从虚拟机内部看
- 启动类加载器(Bootstrap ClassLoader):用C++语言编写,是虚拟机的一部分
- 其他类加载器:使用java实现,独立于虚拟机,继承于抽象类java.lang.ClassLoader
从开发人员角度看
- 启动类加载器(BootStrap ClassLoader)
- 扩展类加载器(Extension ClassLoader)
- 应用程序类加载器(Application ClassLoader)
双亲委托模型
类加载器层次

工作过程
一个类加载器接到了加载类的请求,并不会立即加载,而是传递给它的上层类加载器,若上次类加载器无法加载,才会尝试自己加载
好处
使得 Java 类随着它的类加载器一起具有一种带有优先级的层次关系,从而使得基础类得到统一。
例如 java.lang.Object 存放在 rt.jar 中,如果编写另外一个 java.lang.Object 并放到 ClassPath 中,程序可以编译通过。
由于双亲委派模型的存在,所以在 rt.jar 中的 Object 比在 ClassPath 中的 Object 优先级更高,
这是因为 rt.jar 中的 Object 使用的是启动类加载器,而 ClassPath 中的 Object 使用的是应用程序类加载器。
rt.jar 中的 Object 优先级更高,那么程序中所有的 Object 都是这个 Object。
实现过程
loadClass() 方法运行过程如下:先检查类是否已经加载过,如果没有则让父类加载器去加载。当父类加载器加载失败时抛出 ClassNotFoundException,此时尝试自己去加载。
public abstract class ClassLoader {
// The parent class loader for delegation
private final ClassLoader parent;
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
}
自定义类加载器
1、继承java.lang.ClassLoader
2、不用重写loadClass方法,但是需要重写findClass方法
public class FileSystemClassLoader extends ClassLoader {
private String rootDir;
public FileSystemClassLoader(String rootDir) {
this.rootDir = rootDir;
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classData = getClassData(name);
if (classData == null) {
throw new ClassNotFoundException();
} else {
return defineClass(name, classData, 0, classData.length);
}
}
private byte[] getClassData(String className) {
String path = classNameToPath(className);
try {
InputStream ins = new FileInputStream(path);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
int bytesNumRead;
while ((bytesNumRead = ins.read(buffer)) != -1) {
baos.write(buffer, 0, bytesNumRead);
}
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private String classNameToPath(String className) {
return rootDir + File.separatorChar
+ className.replace('.', File.separatorChar) + ".class";
}
}
JVM系列四:类加载的更多相关文章
- jvm系列四类加载与字节码技术
四.类加载与字节码技术 1.类文件结构 首先获得.class字节码文件 方法: 在文本文档里写入java代码(文件名与类名一致),将文件类型改为.java java终端中,执行javac X:...\ ...
- jvm系列 (五) ---类加载机制
类的加载机制 目录 jvm系列(一):jvm内存区域与溢出 jvm系列(二):垃圾收集器与内存分配策略 jvm系列(三):锁的优化 jvm系列 (四) ---强.软.弱.虚引用 我的博客目录 什么是类 ...
- JVM总括四-类加载过程、双亲委派模型、对象实例化过程
JVM总括四-类加载过程.双亲委派模型.对象实例化过程 目录:JVM总括:目录 一. 类加载过程 类加载过程就是将.class文件转化为Class对象,类实例化的过程,(User user = new ...
- jvm系列(四):jvm知识点总结
原文链接:http://www.cnblogs.com/ityouknow/p/6482464.html jvm 总体梳理 jvm体系总体分四大块: 类的加载机制 jvm内存结构 GC算法 垃圾回收 ...
- jvm系列四、jvm知识点总结
原文链接:http://www.cnblogs.com/ityouknow/p/6482464.html jvm 总体梳理 jvm体系总体分四大块: 类的加载机制 jvm内存结构 GC算法 垃圾回收 ...
- jvm系列 (四) ---强、软、弱、虚引用
java引用 目录 jvm系列(一):jvm内存区域与溢出 jvm系列(二):垃圾收集器与内存分配策略 jvm系列(三):锁的优化 我的博客目录 为什么将引用分为不同的强度 因为我们需要实现这样一种情 ...
- 【JVM】JVM系列之类加载机制(四)
一.前言 前面分析了class文件具体含义,接着需要将class文件加载到虚拟机中,这个过程是怎样的呢,下面,我们来仔细分析. 二.什么是类加载机制 把class文件加载到内存,并对数据进行校验.转换 ...
- jvm系列(四):jvm调优-命令大全(jps jstat jmap jhat jstack jinfo)
文章同步发布于github博客地址,阅读效果更佳,欢迎品尝 运用jvm自带的命令可以方便的在生产监控和打印堆栈的日志信息帮忙我们来定位问题!虽然jvm调优成熟的工具已经有很多:jconsole.大名鼎 ...
- jvm系列(四):jvm调优-命令篇
运用jvm自带的命令可以方便的在生产监控和打印堆栈的日志信息帮忙我们来定位问题!虽然jvm调优成熟的工具已经有很多:jconsole.大名鼎鼎的VisualVM,IBM的Memory Analyzer ...
随机推荐
- WebException 请求被中止: 操作超时
HTTP 请求时出现 :WebException 请求被中止: 操作超时 处理HTTP请求的服务器 CPU 100% ,重启后正常.
- Freemarker讲解
FreeMarker是一个用Java语言编写的模板引擎,它基于模板来生成文本输出.FreeMarker与Web容器无关,即在Web运行时,它并不知道Servlet或HTTP.它不仅可以用作表现层的实现 ...
- 微信小程序 之页面跳转
wxml: <view><button bindtap="abc" >跳转</button></view> js: abc: (e) ...
- npm安装10
https://www.cnblogs.com/zouke1220/p/9723191.html
- LeetCode 378. 有序矩阵中第K小的元素(Kth Smallest Element in a Sorted Matrix) 13
378. 有序矩阵中第K小的元素 378. Kth Smallest Element in a Sorted Matrix 题目描述 给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩 ...
- 综述论文翻译:A Review on Deep Learning Techniques Applied to Semantic Segmentation
近期主要在学习语义分割相关方法,计划将arXiv上的这篇综述好好翻译下,目前已完成了一部分,但仅仅是尊重原文的直译,后续将继续完成剩余的部分,并对文中提及的多个方法给出自己的理解. 论文地址:http ...
- WCF-方法重载
一.服务端重载 一般写法直接重载,但是会报错,如下. [ServiceContract] public interface IService1 { [OperationContract] string ...
- nohup 后台运行脚本,且可以实时查看日志
-u加在python上 python命令加上-u(unbuffered)参数后会强制其标准输出也同标准错误一样不通过缓存直接打印到屏幕. 这是因为python的缓存机制所决定的 如果是使用 nohup ...
- hdu 2167 题解
题目 题意 一个数字正方形(所有数都是两位的正整数),取了一个数后,它的周围 $ 8 $ 个数都不能被选,问最大取数总和. 注意数据范围 $ 3=< n <=15 $ 我们可能一开始会去想 ...
- Spring Boot使用@Value注解获取配置文件中的属性
获取配置文件的内容——