目录
类加载:(作用:把class文件放在虚拟机里面能运行)
类加载机制:
Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程被称作虚拟机的类加载机制。
类的生命周期:
(很多阶段是交叉混合运行的)
但是进行初始化的,只能有六种情况:
1、创建类的实例(使用 new 关键字)
当通过 new 关键字创建类的实例时,会触发该类的初始化。
2、访问类的静态成员
当首次访问类的静态字段或调用类的静态方法时,会触发该类的初始化。
3、使用反射 API 访问类
使用反射 API(如 Class.forName())加载类时,会触发该类的初始化。
4、初始化子类
当一个子类被初始化时,如果它的父类还没有被初始化,则会触发父类的初始化。这是因为在初始化子类之前,JVM 需要确保其父类已经完成初始化,以确保继承的静态成员和静态代码块被正确执行。
5、JVM 启动时初始化主类
在 JVM 启动时,主类(即包含 main 方法的类)会被初始化。
6、定义常量的类
在某些情况下,当类中定义了静态常量,并在其他类中被引用时,可能会触发该类的初始化。特别是当常量在其他类中被直接引用时,JVM 可能会在编译时将其替换为常量值,从而触发类的初始化。
类加载器:
负责将Java类的二进制代码加载到内存中,并转换为可执行的Java字节码。
类加载器的主要职责是根据类的全限定名在运行时定位并读取类的字节码。类加载器使用一种称为双亲委派模型的机制来加载类。该模型根据一定的规则将类加载的任务委派给父加载器,直到最终委派给启动类加载器进行加载。如果父加载器无法加载该类,才由当前加载器自行加载。
双亲委派模型:
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到最顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去完成加载
这种模型保证了类的加载是从上到下的,避免了重复加载和类的版本冲突问题。
破坏双亲委派模型:
- 自定义类加载器: 通过继承ClassLoader类并重写loadClass方法,可以创建一个自定义的类加载器。在这个方法中,可以忽略双亲委派机制,直接从文件系统或者网络加载类。
- 使用线程上下文类加载器: 在某些情况下,可以通过设置线程的上下文类加载器来改变类加载的行为。通过设置不同的类加载器,可以加载同名但不同的类。
- 使用URLClassLoader: URLClassLoader允许从指定的URL加载类,它不遵循双亲委派模型,而是直接加载类。
- 使用系统类加载器加载: 通过使用系统类加载器(ClassLoader.getSystemClassLoader())加载类,可以绕过双亲委派机制。
- 代理类加载器: 创建一个代理类加载器,它在加载类时,可以决定是否调用父类加载器。
- 使用反射: 在某些情况下,可以使用反射API来加载类,但这通常不会破坏双亲委派机制。
- 修改JVM实现: 如果你有JVM的源代码,可以修改JVM的实现,从而改变类加载的行为。