类的生命周期

加载-》验证-》准备-》解析-》初始化-》使用-》卸载

类加载过程

类加载包括以上的前五个过程:加载,验证,准备,解析,初始化

加载

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系列四:类加载的更多相关文章

  1. jvm系列四类加载与字节码技术

    四.类加载与字节码技术 1.类文件结构 首先获得.class字节码文件 方法: 在文本文档里写入java代码(文件名与类名一致),将文件类型改为.java java终端中,执行javac X:...\ ...

  2. jvm系列 (五) ---类加载机制

    类的加载机制 目录 jvm系列(一):jvm内存区域与溢出 jvm系列(二):垃圾收集器与内存分配策略 jvm系列(三):锁的优化 jvm系列 (四) ---强.软.弱.虚引用 我的博客目录 什么是类 ...

  3. JVM总括四-类加载过程、双亲委派模型、对象实例化过程

    JVM总括四-类加载过程.双亲委派模型.对象实例化过程 目录:JVM总括:目录 一. 类加载过程 类加载过程就是将.class文件转化为Class对象,类实例化的过程,(User user = new ...

  4. jvm系列(四):jvm知识点总结

    原文链接:http://www.cnblogs.com/ityouknow/p/6482464.html jvm 总体梳理 jvm体系总体分四大块: 类的加载机制 jvm内存结构 GC算法 垃圾回收 ...

  5. jvm系列四、jvm知识点总结

    原文链接:http://www.cnblogs.com/ityouknow/p/6482464.html jvm 总体梳理 jvm体系总体分四大块: 类的加载机制 jvm内存结构 GC算法 垃圾回收 ...

  6. jvm系列 (四) ---强、软、弱、虚引用

    java引用 目录 jvm系列(一):jvm内存区域与溢出 jvm系列(二):垃圾收集器与内存分配策略 jvm系列(三):锁的优化 我的博客目录 为什么将引用分为不同的强度 因为我们需要实现这样一种情 ...

  7. 【JVM】JVM系列之类加载机制(四)

    一.前言 前面分析了class文件具体含义,接着需要将class文件加载到虚拟机中,这个过程是怎样的呢,下面,我们来仔细分析. 二.什么是类加载机制 把class文件加载到内存,并对数据进行校验.转换 ...

  8. jvm系列(四):jvm调优-命令大全(jps jstat jmap jhat jstack jinfo)

    文章同步发布于github博客地址,阅读效果更佳,欢迎品尝 运用jvm自带的命令可以方便的在生产监控和打印堆栈的日志信息帮忙我们来定位问题!虽然jvm调优成熟的工具已经有很多:jconsole.大名鼎 ...

  9. jvm系列(四):jvm调优-命令篇

    运用jvm自带的命令可以方便的在生产监控和打印堆栈的日志信息帮忙我们来定位问题!虽然jvm调优成熟的工具已经有很多:jconsole.大名鼎鼎的VisualVM,IBM的Memory Analyzer ...

随机推荐

  1. PMP备考笔记--1.1

    题型 200道中英文单选题 基本概念题(%10) 过程工具/技术和输入输出题ITTO (%10) 情景题(%70) 计算题(3-5道题) 图 pmp四大挑战 试卷100页,题干长,阅读量大,考试4个小 ...

  2. Java创建线程的两种方法

    大多数情况,通过实例化一个Thread对象来创建一个线程.Java定义了两种方式: 实现Runnable 接口: 可以继承Thread类. 下面的两小节依次介绍了每一种方式. 实现Runnable接口 ...

  3. [C语言]给定直角三角形面积和斜边长

    [A题]   翘课的HugeGun_ 时间限制:1000ms   内存限制:65536kb 题目描述 HugeGun学姐很喜欢翘课.不幸的是,这一次她被发现了. 老师让她打扫了教室.当她把扫把靠在墙上 ...

  4. DateTimeFormatter 的操作与使用 -- 通俗易懂

    在上一章我们讲解了LocalDate.LocalTime.LocalDateTime.Instant的操作与使用,下面讲解它们之间是如何进行格式化 DateTimeFormatter这个类它只提供了时 ...

  5. 通过tushare获取股票价格

    # Author llll # coding=utf-8 # ---描述# 完成股票 价格查询和展示# 不直接根据网页进行爬虫获取股票价格,而是通过已有组件查询股票价格,并保存到csv文件或者exce ...

  6. Python yield 使用浅析【转】

    Python yield 使用浅析 IBM developerWorks 中国 : Open source IBM 开源 - IBM Developer 中国 (原 developerWorks 中国 ...

  7. 在论坛中出现的比较难的sql问题:34(递归 获取连续值问题)

    原文:在论坛中出现的比较难的sql问题:34(递归 获取连续值问题) 所以,觉得有必要记录下来,这样以后再次碰到这类问题,也能从中获取解答的思路.

  8. Asp.netCore 的Startup 不继承接口

    有一个问题: Asp.netCore 的Startup 要实现 Config 和ConfigServie 方法, 为什么不接口约束呢. 进入源码: // // 摘要: // /// Specify t ...

  9. 日常hive遇到的问题

    1 hive中的复杂数据类型数据如何导入(array) 创建hive表 create table temp.dws_search_by_program_set_count_his( program_s ...

  10. Go 编译 && 工具

    编译和工具链 Go 的工具链非常丰富,从获取源码.编译.文档.测试.性能分析,到源码格式化.源码提示.重构工具等应有尽有 在 Go 中可以使用测试框架编写单元测试,使用统一的命令行即可测试及输出测试报 ...