类加载的方式有2种。
l
显示类加载
ClassLoader.loadClass()(使用指定的Classloader进行装载)
Class.forName()(使用当前类的Caller Classloader进行装载)
l
隐示类加载(发生在由于引用、实例化或继承导致需要装载类的时候。隐式类装载是在幕后启动的,JVM会解析必要的引用并装载类。)
Classloader可能先显式地装载一个类,然后再隐式地装载它引用的其它类。
从类装载方式的描述中我们可以看到,
只有在显式的调用方法或者实例化、引用、继承一个类时,类才真正被装载
。由此,我们可以知道,import并不会导致类装载,以及,在一个类实例化之前,调用它的静态方法,会导致这个类和它的父类、实现的接口和相关的静态成员的类会被装载,而它的成员变量的类却不会被装载
ClassLoader中有个ClassLoader类型的parent的属性,表示需要loadClass的时候先找parent加载。
这跟职责链模式有点类似,职责链是自己处理不了就交给下一个处理器处理。而在ClassLoader中,是先找到自己的parent加载类,递归地找到最高层次的parent,如果不成功,再让本ClassLoader进行类加载。如果parent为null,则认为是JVM中的BootStrapClassLoader。
在JVM启动后,类的加载方式有2种,一种是预先加入(pre-loading),另外一种是按需载入(load-on-demand)。

如图,在JVM启动以后首先启动BootStrapClassLoader,BootStrapClassLoader开始加载核心API类,在加载sun.misc下的Launcher.java以后加载2个内部类。
第一个是ExtClassLoader,负责把Java的扩展库载入。同时将ExtClassLoader的parent设为null,也就是BootStrapClassLoader。
第二个是AppClassLoader,负责把CLASSPATH路径下的类库和用户自定义类加载到内存中。其parent是ExtClassLoader。

类的加载器可以用Class.getClassLoader()方法来获得。如下示例:
System.out.println(App.class.getClassLoader());//App是自定义类
System.out.println(String.class.getClassLoader());
返回结果是:
sun.misc.Launcher$AppClassLoader@19821f
null
数组类的Class对象不是由类加载器创建的,而是由Java运行时根据需要自动创建。如果是基本数据类型,则没有类加载器。
自定义的ClassLoader可以继承URLClassLoader或ClassLoader。当继承ClassLoader重写findClass()方法,parent会相应是AppClassLoader-->ExtClassLoader-->BootStrapClassLoader。
只有在实例化一个类的时候才会被ClassLoader载入,仅仅申明并不会。
ClassLoader 中最关键的loadClass()源码:
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
// 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;
}
可以看见第一步是先查找该类是否已经加载,如果未加载,查看parent是否为空,不空的话就交给parent处理,空的话就交给 findBootstrapClassOrNull()方法,该方法让BootStrapClassLoader加载类。如果从parent那里加载失败 (抛出异常了),那么就让自己加载类(调用本类被继承的方法findClass())。之后判断resolve,如果为真就
连接。
说到连接,参考《深入Java虚拟机》。
类装载器子系统除了要定位和导入二进制文件外,还必须确认验证被导入类的正确性,为类变量分配并初始化内存。这些动作的顺序是:1)装载;2)连接:a.验证;b.准备;c.初始化;3)初始化。

装载就是查找并将二进制数据装到虚拟机中。
连接开始时执行验证,验证后就准备,准备的过程是为类变量(静态变量)分配内存并将其初始化为默认值。解析这一步是可选的,是将类型中的符号引用转换为直接引用。之后进行初始化,这时候把类变量初始化为正确的值(有进行引用赋值的情况下)。
分享到:
相关推荐
《深入理解ClassLoader》 在Java世界中,ClassLoader是运行时加载类的核心机制,它负责将类的.class文件加载到JVM中,使得程序能够运行。本文将深入剖析ClassLoader的工作原理,以及其在实际开发中的应用。 一、...
如果当前线程的ClassLoader无法获取到资源,Spring会转而使用加载org.springframework.util.ClassUtils类的ClassLoader。 在Spring加载配置文件时,我们需要注意几个关键点: 1. **不使用通配符**:当配置文件路径...
【浅析J2EE应用服务器的JAVA类装载器】 Java类装载器机制是Java语言灵活性的关键组成部分,尤其在J2EE应用服务器中扮演着重要角色。理解这一机制有助于开发者更好地部署和管理应用程序,解决可能出现的部署问题。 ...
4. 如果要加载的资源,不在当前 ClassLoader 的路径里,那么用 classpath: 前缀是找不到的,这种情况下就需要使用 classpath*: 前缀。 5. 在多个 classpath 中存在同名资源,都需要加载时,那么用 classpath: 只会...
4、类加载器ClassLoader 4.1类加载器分类 5、双亲委派机制 5.1、检查某个类是否已经加载 5.2、加载顺序 5.3、打破双亲委派机制 所谓类加载机制就是 虚拟机把Class文件加载到内存 并对数据进行校验,...
5. **JVM ClassLoader机制**:ClassLoader负责加载类到JVM中,包括Bootstrap ClassLoader、Extension ClassLoader和App ClassLoader。类加载遵循双亲委派模型,确保类加载的唯一性。 6. **Java中的synchronized使用...