类加载器小结

最近遇到了一些问题,然后就了解了一些类加载的过程。在学习过程中,发现类加载器在其中起到了很大的作用,今天就把前几天看的类加载器的东西给稍作总结一下吧.

目录:

  1. 什么是类加载器
  2. 类加载器的常用方法
  3. 类加载器结构
  4. 类加载器的加载机制
  5. 类被初始化的时机(扩展)
  6. 相关知识

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()方法的那个类先初始化

6. 相关知识

有关类初始化的面试题1
有关类初始化的面试题2

参考文章:

Java ClassLoader
深入探讨 Java 类加载器
类加载器官方文档

推荐阅读更多精彩内容