最近遇到了一些问题,然后就了解了一些类加载的过程。在学习过程中,发现类加载器在其中起到了很大的作用,今天就把前几天看的类加载器的东西给稍作总结一下吧.
目录:
- 什么是类加载器
- 类加载器的常用方法
- 类加载器结构
- 类加载器的加载机制
- 类被初始化的时机(扩展)
- 相关知识
1.什么是类加载器
A class loader is an object that is responsible for loading classes. The class ClassLoader is an abstract class. Given the binary name of a class, a class loader should attempt to locate or generate data that constitutes a definition for the class. A typical strategy is to transform the name into a file name and then read a "class file" of that name from a file system. --- Oracle official document
We know that Java Program runs on Java Virtual Machine (JVM). When we compile a Java Class, it transforms it in the form of bytecode that is platform and machine independent compiled program and store it as a .class file. After that when we try to use a Class, Java ClassLoader loads that class into memory. ---http://www.journaldev.com
顾名思义,类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。 ---IBM中文论坛社区
从上边的各种解释中可以简单总结出:类加载器就是把class文件加载到虚拟机,或者说是内存中。
2. 类加载器的常用方法
loadClass(String name);
findClass(String name);
defineClass(String name, byte[] b, int off, int len);
getParaent();
3. 类加载器结构
3.1 类加载器包括哪些:
- 引导类加载器 (负责加载核心库 由c++实现)
- 扩展类加载器 (负责扩展库 由c++实现)
- 系统类加载器 (负责加载CLASSPATH)
- 继承ClassLoader实现自定义类加载器
3.2 类加载器的树状组织结构:
4. 类加载器的加载机制
结合3.2给出的那副树状组织结构图,来说一下类加载器的加载机制:代理模式/双亲委派机制
什么是代理模式呢?
某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
这样做的目的是什么?
这样做的目的是防止内存中出现多份同样的字节码,还可以保证java核心库的安全(因为不同的类加载器实例加载相同的类,它们的类型也不一致)
下边附上一段代码来测试虽然是同一个类,但是由不同的类加载器加载之后,它们的类型也是不一样的。
public void testClassIdentity() {
String classDataRootPath = "C:\\workspace\\Classloader\\classData";
FileSystemClassLoader fscl1 = new FileSystemClassLoader(classDataRootPath);
FileSystemClassLoader fscl2 = new FileSystemClassLoader(classDataRootPath);
String className = "com.example.Sample";
try {
Class<?> class1 = fscl1.loadClass(className);
Object obj1 = class1.newInstance();
Class<?> class2 = fscl2.loadClass(className);
Object obj2 = class2.newInstance();
Method setSampleMethod = class1.getMethod("setSample", java.lang.Object.class);
setSampleMethod.invoke(obj1, obj2);
} catch (Exception e) {
e.printStackTrace();
}
}
5. 类被初始化的时机(扩展)
- 类被初始化的时机(扩展)
- 访问类的静态变量(访问final常量不会触发初始化)
- 访问类的静态方法
- 反射
- 当初始化一个类时,发现其父类还未初始化,则先出发父类的初始化
- 虚拟机启动时,定义了main()方法的那个类先初始化