.java编译后会生成 .class 文件,这个文件是存放在物理磁盘上的,所谓的类加载,就是将物理磁盘上的class文件加载到内存(也就是JVM)中。

一、步骤:
1、加载之前,必须先经过校验,检查class文件是否是合格的字节码文件。
2、校验通过之后,会有一个准备阶段,这个阶段只要是给一些静态成员变量赋初始值,如果是带final的常量,是不会有默认值的,直接赋值。如下面的语句,默认值会被设置为0.
public static int dataVallue = 888; //会被设置为0,而非888。
但是常量会被直接赋值为真正的值:
public static final int dataVallue_2 = 888; //会直接赋值为 888
3、准备阶段之后,进入到一个解析阶段,这个阶段主要是进行静态链接,所谓的静态链接就是将一些静态方法,用指针表示,换句话说,就是用指针指向静态方法,更专业的术语应该可以这样描述,就是将静态符号转为直接引用。和静态链接对应的是动态链接,动态链接是运行时生成的指针指向非静态方法的称谓。静态方法会被加载进方法区。最常见的静态方法非我们的main方法莫属了。
public static void main(String[] args)
4、准备阶段之后,进入初始化阶段,会把上面的静态成员变量赋上真正的值。
二、类的加载器
1、引导类加载器(C++实现)。
加载jre的lib目录下的一些核心类,比如rt.jar、charsets.jar等,String等核心类就是引导类加载的。使用如下代码可以查看根加载器的加载内容:
public class TestBootClassLoader {
public static void main(String[] args) {
System.out.println("BootClassLoader加载以下文件:");
URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
for (int i = 0; i < urLs.length; i++) {
System.out.println(urLs[i]);
}
}
}
//输出:
// file:/D:/java/jdk1.8.0_131/jre/lib/resources.jar
// file:/D:/java/jdk1.8.0_131/jre/lib/rt.jar
// file:/D:/java/jdk1.8.0_131/jre/lib/sunrsasign.jar
// file:/D:/java/jdk1.8.0_131/jre/lib/jsse.jar
// file:/D:/java/jdk1.8.0_131/jre/lib/jce.jar
// file:/D:/java/jdk1.8.0_131/jre/lib/charsets.jar
// file:/D:/java/jdk1.8.0_131/jre/lib/jfr.jar
// file:/D:/java/jdk1.8.0_131/jre/classes
2、扩展类加载器(Java实现)。
加载jre的lib目录下的ext目录下的一些类。
3、应用类加载器(Java实现)。
加载程序员自己写的类。
4、自定义类加载器,继承ClassLoader类即可,实现一下findClass方法,自定义类加载器应该继承于应用类加载器。
三、双亲委派机制

当应用类加载器收到请求要加载类进内存的时候,应用类加载器会向上汇报,到达扩展类加载器,扩展类加载器会再次上报,到达引导类扩展器,引导类扩展器如果发现需要加载的类自己加载不了,会叫扩展类加载,扩展类发现也加载不了,会让应用类加载。
那为什么要这样设计呢?
1、**为了防止重复加载。**如果应用类加载器不向上汇报,这时如果引导类或者扩展类已经加载过了,那么应用类就没必要再次加载。
2、**保护核心类。**如果用户自己修改了核心类,那么上报的时候,会被直接拒绝加载。
有一个特点值得大家留意。如果某一个类用了某一个加载器加载,那么这个类的类引用都会默认用当前的加载器。这种方式称为 “全盘委托机制”
Java类加载包括加载、校验、准备、解析和初始化五个步骤,其中加载涉及类加载器,如引导类加载器、扩展类加载器和应用类加载器。双亲委派机制确保类只被加载一次并保护核心类库不受用户代码篡改。类的加载过程包括静态成员变量的初始化和静态方法的加载。

被折叠的 条评论
为什么被折叠?



