3、获取某个类的反射对象
4、初始化子类,如果父类没有初始化,会先触发父类的初始化(不适用接口)
5、如果一个接口定义了 default 方法,那么直接实现或者间接实现该接口的类的初始化,该接口要在其之前被初始化 。
6、虚拟机启动,调用主方法的类会被初始化
7、初次调用 MethodHanlder 实例时,初始化该 MethodHanlder 指向的方法所在的类 。( 涉及解析REF_getStatic、REF_putStatic、REF_invokeStatic方法句柄所在的类)
被动使用的场景1、访问的类属性不是当前类的属性,比如从父类继承而来的或者实现接口得到的,比如
public class InitTest{public static void main(String[] args) {int a = son.a;}}class parent{public static int a =0;static {System.out.println("12");}}class son extends parent{public static int b =0;static {System.out.println("1ss2");}}这里只会触发 parent 的初始化,而不会触发 son 类的初始化,而如果 son 重写了属性 a 或者调用的是 son 的另一个属性 b ,那么就会触发 son 类的初始化,并且因为 son 继承了 parent 类,所以在 son 初始化前还会先初始化 parent 。
2、通过数组定义类引用,不会触发此类的初始化(如果数组类型是基本数据类型,那么不需要加载;如果是引用数据类型,那么就进行类的加载,但不会进行初始化操作)
3、调用 static final 修饰的且是常量或者是字符串或是其他没有方法触发的情况,也不会触发初始化操作 。
4、调用 ClassLoader 的 loadClass() 方法加载一个类,只会触发加载操作,而不会触发初始化操作 。
类加载器的拓展类的唯一性每个类加载器都有其自己的命名空间,命名空间由该加载器及其所有的父加载器所加载的类组成 。在同一个命名空间中,不会出现类的完整名字(包名+类名)相同的两个类 。但在不同的命名空间中,有可能出现完整名字相同的两个类 。
所以,在比较两个类是否是同一个类的前提是这两个类由同一个类加载器加载,如果这两个类是由两个类加载器加载的,那么这两个类必然不是同一个类 。一个类只能被一个类加载器加载一次,但是可以被多个类加载器加载 。
类加载器的主要方法1、getParent()返回该类加载器的父类加载器 。
2、loadClass(name)加载 name 类,如果找不到该类,就抛出异常 。内部的实现是父类委托机制 。
3、findClass(name)查找二进制的 name 类,返回该类的实例,这个类是 loadClass 内部调用的一个方法,JDK 维护了一个推荐的重写方法,鼓励我们去重写这个方法来实现对功能的拓展 。JDK 1.2 之前还未引入父类委托机制,所以要拓展就需要去重写 loadClass 方法,1.2 引入父类委托机制后通过重写 findClass 方法来拓展,并且也没有破坏父类委托机制 。
4、defineClass(String name, byte[] b,int off, int len)将字节数组 b 转换为 Class 的实例,off 和 len 参数表示实际 Class 信息在 byte 数组中的位置和长度 。其中 b 是ClassLoader 从外部获取的 。这是受保护的方法,只有在自定义的 ClassLoader 子类中使用 。一般在 findClass 方法中被调用,在 findClass 方法中先类的字节码数组,然后调用 defineClass 获取类实例返回 。

文章插图
ClassLoader 一些实现类的继承关系SecureClassLoader 扩展了 ClassLoader,增加一些方法,但是一般我们使用的是其子类 URLClassLoader,URLClassLoader 实现了 ClassLoader 很多抽象方法,如 findClass()、findResource()。我们在编写自定义类加载器时,如果没有特别复杂的实现,可以直接继承 URLClassLoader ,这样可以避免自己编写 findClass 以及获取字节流的方式,使自定义类加载更加简洁。而拓展类加载器与系统类加载器也是继承 URLClassLoader。

文章插图
Class.forName 与 ClassLoader.loadClass 的区别ClassLoader.loadClass 是一个实例方法,该方法将 Class 文件加载到内存中后,只会执行类加载过程的加载、验证、准备、 解析 。初始化等到类的第一次使用时才会执行 。Class.forName 是静态方法,该方法在将 Class 文件加载到内存的同时,还会执行类的初始化 。
破坏双亲委派机制的三次场景1、由于双亲委派机制是在 JDK1.2 之后才引入的,而在 Java 的第一个版本就有类加载器的概念以及抽象类 ClassLoader ,所以此时是没有双亲委派机制的,用户自定义类加载器就是直接重写 loadClass 方法,这也就是破坏了双亲委托机制 。
推荐阅读
- 这应该是全网讲解JAVA 异常处理最全的文章了
- 超实用的tomcat启动脚本实现
- 一张纸的童话故事?关于纸的童话故事
- 一文详解 C++ 框架:日志框架
- Linux文件系统EXT2,EXT3,ReiserFS详解
- 本地文件指哪些?
- 朋友结婚随礼多少钱合适?
- 十分钟从Java 8到Java 15
- 5分钟搭建公网https网页文件服务器,免费权威TLS证书
- 最新的JavaScript核心语言标准
