Java 中类的加载时机
Java 中的类加载采用延迟加载的机制,只有在类被实际使用时才会触发加载。
以下是具体的触发场景:
1. 类的实例被创建时
通过关键字
new
创建类的对象时,JVM 会检查该类是否已经加载。如果类未被加载,则触发类的加载。
示例:
MyClass obj = new MyClass(); // 触发加载 MyClass 类
2. 访问类的静态变量或静态方法时
当调用类的静态变量或静态方法时,如果该类还未被加载,则会触发类加载。
示例:
System.out.println(MyClass.staticField); // 触发加载 MyClass 类
MyClass.staticMethod(); // 触发加载 MyClass 类
3. 使用反射机制时
使用
Class.forName()
或其他反射 API 加载类时,JVM 会检查类是否已经加载。如果未加载,则触发加载。
示例:
Class<?> clazz = Class.forName("com.example.MyClass"); // 触发加载 MyClass 类
4. JVM 启动时加载基础类
JVM 会在启动时自动加载一些基础类,例如
java.lang.Object
和java.lang.String
。
说明:
这些类是 JVM 的运行基础,必须在启动时加载。
5. 动态语言调用时
使用 JDK 7 引入的动态语言支持时,若方法句柄解析到未加载的类,则触发类加载。
示例:
MethodHandle mh = MethodHandles.lookup().findStatic(MyClass.class, "methodName", MethodType.methodType(void.class));
扩展知识:类加载器和数组加载
1. 数组的加载
数组是类,但不通过类加载器加载,而是由 JVM 运行时自动创建。
如果数组的元素类型是对象类型,则数组的类加载器与其元素类型的类加载器相同;如果是基本类型,则没有类加载器。
示例:
int[] intArray = new int[10]; // 没有类加载器
MyClass[] objArray = new MyClass[10]; // 使用 MyClass 的类加载器
2. 类加载器的流程
使用双亲委派模型加载类:
检查缓存,若类已加载,则直接返回。
委派给父加载器加载类。
若父加载器无法找到类,则调用子类实现的
findClass()
方法。使用
defineClass()
方法将类的二进制数据转为Class
对象。
总结
Java 中的类加载时机主要包括以下几种:
创建类实例。
访问类的静态成员。
使用反射机制。
JVM 启动时加载基础类。
动态语言调用时触发。
延迟加载的机制使得 JVM 的资源使用更高效,同时为动态加载类提供了灵活性。