类的生命周期描述了一个类加载、使用、卸载的整个过程
生命周期概述
加载、连接、初始化、使用、卸载
连接包含(验证、准备、解析)
加载阶段
1、加载阶段第一步是类加载器根据类的全限定名通过不同的渠道以二进制流的方式获取字节码信息。
本地文件:磁盘上的字节码文件
动态代理生成:程序运行时使用动态代理生成
通过网络传输的类:早期的Applet技术使用。
连接阶段
(1)验证
(2)准备:准备阶段为静态变量(static)分配内存并设置初始值
涉及的内存结构只是jdk8和jdk8之后的版本,准备阶段只会给静态变量赋初始值,而每一种基本数据类型和引用数据类型都有其初始值。
在初始阶段就为这些静态变量附上初始值。
final修饰的基本数据类型的静态变量,准备阶段直接会将代码中的值进行赋值。
public class Student{
public static final int value = 1;
}
(3)解析
解析阶段主要是将常量池中的符号引用替换为直接引用
符号引用就是在字节码文件中使用编号来访问常量池中的内容。
直接引用就是不使用编号,而是使用内存中地址进行访问具体的数据。
初始化阶段
初始化阶段会执行静态代码块中的代码,并为静态变量赋值。
初始化阶段会执行字节码文件中clinit(class init)部分的字节码指令。
以下几种方式会导致类的初始化:
1、访问一个类的静态变量或者静态方法,注意变量是final修饰的并且等号右边是常量不会触发初始化。
2、调用Class.forName(String className)
3、new一个该类的对象时。
4、执行Main方法的当前类。
类加载器的分类-类加载器
扩展类加载器和应用程序类加载器都是JDK中提供的、使用Java编写的类加载器。
它们的源码都是位于sun.misc.Launcher中,是一个静态内部类。继承自URLClassLoader。或者指定jar包将字节码文件加载到内存中。类加载器的分类
类加载器的设计JDK8和8之后的版本差别较大,JDK8及之前的版本中默认的类加载器有如下几种:
虚拟机底层实现的C++,启动类加载器Bootstrap 加载Java最核心的类。
Java编写的,
扩展类加载器Extension ,允许扩展Java中比较通用的类。
应用程序类加载器,Appliction 加载应用使用的类。
类加载器的双亲委派机制,由于Java虚拟机中有多个类加载器,双亲委派机制的核心是解决一个类到底由谁来加载的问题。
启动类加载器Bootstrap
扩展类加载器 Extension
应用程序类加载器 Application
双亲委派机制有什么用?
(1)保证类加载的安全性
通过双亲委派机制避免恶意代码替换JDK中的核心类库,比如
java.lang.String,确保核心类库的完整性和安全性。
(2)避免重复加载
双亲委派机制可以避免同一个类被加载多次。
双亲委派机制指的是:当一个类加载器接收到加载类的任务时,会自底向上查找是否加载过,再由顶向下进行加载。向上查找如果已经加载过,就直接返回Class对象,加载过程结束。这样就能避免一个类重复加载。
如果所有的父类加载器都无法加载该类,则由上至下,加载器自己尝试自己加载。所以看上去是自顶向下尝试加载。
类的双亲委派机制是什么?
1、当一个类加载器去加载某个类的时候,会自底向上查找是否加载过,如果加载过就直接返回,如果一直到最顶层的类加载器都没有加载,再由顶向下进行加载。
2、应用程序类加载器的父类加载器是扩展类加载器,扩展类加载器的父类加载器是启动类加载器。
3、双亲委派机制的好处有两点:第一是避免恶意代码替换JDK中的核心类库,比如java.lang.String,确保核心类库的完整性和安全性。第二是避免一个类重复地被加载。如何打破双亲委派机制
1、自定义类加载器,来打破双亲委派机制,
先来分析ClassLoader的原理,ClassLoader中包含了4个核心方法。
双亲委派机制的核心代码就位于loadClass方法中。
2、线程上下文类加载器
利用上下文类加载器加载类,比如JDBC和JNDI等
3、历史上Osgi框架的类加载器,历史上Osgi框架实现了一套新的类加载机制,允许同级别之间委托进行类的加载。
Java9之后的类加载器包括。