美文网首页
Java类加载器

Java类加载器

作者: PaulLuv | 来源:发表于2018-06-05 11:26 被阅读6次

1. 类加载器

类加载器:实现这个动作(通过一个类的全限定名来获取描述此类的二进制字节流)的代码模块被称为"类加载器"

类加载器不仅仅只用于实现类的加载动作,它还与类的相等判定有关
判断类相等,有三个条件:

  • 两个类来自同一个Class文件
  • 两个类是由同一个虚拟机加载
  • 两个类都是同一个类加载器加载
public class ClassLoaderTest {
    public static void main(String[] args) throws Exception{
        ClassLoader myLoder = new ClassLoader() {
            @Override
            public Class<?> loadClass(String name) throws ClassNotFoundException {
                try {
                    String fileName = name.substring(name.lastIndexOf(".")) + ".class";
                    InputStream is = getClass().getResourceAsStream(fileName);
                    if (is == null){
                        return super.loadClass(name);
                    }
                    byte[] b = new byte[is.available()];
                    is.read(b);
                    return defineClass(name,b,0,b.length);
                }catch (IOException e){
                    throw new ClassNotFoundException(name);
                }
            }
        };
        // 通过重写loadClass方法,实现自己的加载器。结果发现出现了两个ClassLoaderTest类,
        // 原因就是一个是系统类加载器加载的,另外一个则是由我们实现的类加载器加载。
        Object obj = myLoder.loadClass("classloader.ClassLoaderTest").newInstance();

        System.out.println(obj.getClass()); // class classloader.ClassLoaderTest
        System.out.println(obj instanceof classloader.ClassLoaderTest); // false
    }
}

JVM在运行时产生三个ClassLoader:

  1. Bootstrap ClassLoader : 启动类加载器,也叫根加载器。负责加载 <JAVA_HOME>\lib 目录中的类库,也就是Java核心类。由C++实现,无法被Java程序直接引用。
  2. Extension ClassLoader 扩展类加载器,负责加载 <JAVA_HOME>\lib\ext目录中的类库,用户可以将自己开发的类打包成jar包放在这个目录,即可扩展核心类以外的新功能。
  3. System ClassLoader \ App ClassLoader: 系统类加载器或称为应用程序加载器,一般情况下是程序中默认的类加载器。负责加载用户类路径(ClassPath)上所指定的类库。

2. 双亲委派机制

当一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器无法完成这个加载请求时,子类加载器才会尝试去自己加载。

类加载器之间的父子关系是采用组合关系来复用父加载器的代码。

public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }
protected synchronized Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
    {
    // 首先,检查请求的类是否已经被加载过了
    Class c = findLoadedClass(name);
    if (c == null) {
        try {
            if (parent != null) {
                c = parent.loadClass(name, false);
            } else {
                c = findBootstrapClassOrNull(name);
            }
        } catch (ClassNotFoundException e) {
                // 如果父类加载器抛出 ClassNotFoundException
                // 则说明父类加载器无法完成加载请求
        }
        if (c == null) {
            // 在父类加载器无法加载的时候
            // 再调用本身的findClass方法来进行类加载
            c = findClass(name);
        }
    }
    if (resolve) {
        resolveClass(c);
    }
    return c;
}

使用双亲委派机制,保证了无论哪一个类加载器要加载这个类,最终都是委派给启动类加载器进行加载,因此保证了类的唯一性。

3. 全盘负责

全盘负责是指 当一个ClassLoader装载一个类时,除非显示的使用另一个ClassLoader,则该类所依赖及引用的类也由这个ClassLoader载入。

相关文章

网友评论

      本文标题:Java类加载器

      本文链接:https://www.haomeiwen.com/subject/pdrhsftx.html