类的加载与ClassLoader的理解
一、了解:类的加载过程
当程序主动使用某个类时,如果该类还未加载到内存中,则系统会通过如下三个步骤来对该类进行初始化。
1)加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时
数据结构,然后生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问
入口(即引用地址)。所有需要访问和使用类数据只能通过这个Class对象。这个加载的
过程需要类加载器参与。
2)将Java类的二进制代码合并到JVM的运行状态之中的过程
- 验证:确保加载的类信息符合JVM规范,例如:以cafe开头,没有安全方法的问题。
- 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配。
- 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
3) 初始化:
- 执行类构造器<clinit>() 方法的过程。类构造器<clinit>()方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造器该类对象的构造器)。
- 当初初始化一个类的时候,如果发现其父还没有进行初始化,则需要先触发其父类的初始化。
- 虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步。
实例 :代码块
public class ClassLoadingTest {
public static void main(String[] args) {
System.out.println(A.m);
}
}
class A {
static {
m = 300;
}
static int m = 100;
}
注解:
第一步:链接结束后m=0
第二步:初始化后,m的值由<clinit>()方法执行决定
这个A的类构造器<clinit>()方法由类变量的赋值和静态代码块中的语句按照顺序合并
产生,类似于
<clinit>(){
m = 300;
m = 100;
}
二、了解:ClassLoader
类加载器作用是用来把类(class)装载进内存的。JVM规范定义了如下类型的类的加载器。

1)获取一个系统类加载器
- ClassLoader classloader = ClassLoader.getSystemClassLoader();
- System.out.println(classloader);
2)获取系统类加载器的父类加载器,即扩展类加载器
classloader = classloader.getParent(); System.out.println(classloader);
3)获取扩展类加载器的父类加载器,即引导加载器
classloader = classloader.getParent(); System.out.println(classloader)
4)测试当前类由哪个类加载进行加载
- classloader = Class.forName("exer2.ClassloaderDemo").getClassLoader();
System.out.println(classloader);
5)测试JDK提供的Object类由哪个类加载器加载
classloader = Class.forName("java.lang.Object").getClassLoader(); System.out.println(classloader);
6)关于类加载器的一个主要方法:getResourceAsStream(String str):获取类路
径下的指定文件的输入流
InputStream in = null; in = this.getClass().getClassLoader().getResourceAsStream("exer2\\test.properties"); System.out.println(in);
额外的知识点:
java应用程序的运行机制
Java 语言是两种类型的结合;
利用编辑器编写 Java源程序à源文件名:主类名.java
利用编译器(javac)将源程序编译成字节码文件,字节码文件名:源文件名.class
利用虚拟机(解释器,java)解释执行
运行过程:载入、代码校验、解释执行

