学习JAVA类加载器

类加载器的作用


类加载器(class loader)是用来加载 Java 类到 Java 虚拟机中的。它使得 Java 类可以被动态加载到 Java 虚拟机中并执行。


类加载器的分类


类加载器有两个分类,一种是用于加载JAVA核心组件的启动类加载器(bootstrap class loader),另一种是用户自定义的类加载器,定义这样的加载器需要继承java.lang.ClassLoader

但是如果没有什么特别需求,也无需要自定义类加载器,JAVA已经默认提供了一些自定义的类加载器,一般够用了。

启动类加载器到底是加载什么类呢?

public class ClassLoaderTest {

    public static void main(String[] args) {
        String property = System.getProperty("sun.boot.class.path");
        for(String e : property.split(";")){
            System.out.println(e);
        }
    }
}

上面代码在我的Window机器上的执行结果如下:

C:\Program Files\Java\jdk1.7.0_25\jre\lib\resources.jar
C:\Program Files\Java\jdk1.7.0_25\jre\lib\rt.jar
C:\Program Files\Java\jdk1.7.0_25\jre\lib\sunrsasign.jar
C:\Program Files\Java\jdk1.7.0_25\jre\lib\jsse.jar
C:\Program Files\Java\jdk1.7.0_25\jre\lib\jce.jar
C:\Program Files\Java\jdk1.7.0_25\jre\lib\charsets.jar
C:\Program Files\Java\jdk1.7.0_25\jre\lib\jfr.jar
C:\Program Files\Java\jdk1.7.0_25\jre\classes

可见启动类加载器加载的是jre目录下lib目录中的类。

而JAVA提供的自定义类加载器ExtClassLoader加载的类如下:

ExtClassLoader

public class ClassLoaderTest {

    public static void main(String[] args) {
        String property = System.getProperty("java.ext.dirs");
        for(String e : property.split(";")){
            System.out.println(e);
        }
    }
}

结果:

C:\Program Files\Java\jdk1.7.0_25\jre\lib\ext
C:\Windows\Sun\Java\lib\ext

至于AppClassLoader就是用于加载classpath下的类的。

AppClassLoader和ExtClassLoader是自定义的类加载器,并且是继承自java.lang.ClassLoader,有两种办法来证明这个事情,一种是去看openjdk的源代码,另一种是直接用JAVA代码输出,例如:

public class TempTestClass {
    public void test()
    {
    }
}
public class ClassLoaderTest {

    public static void main(String[] args) {
        TempTestClass hello = new TempTestClass();
        hello.test();

        System.out.println("看看TempTestClass是由哪个类加载器加载的---begin");
        ClassLoader classLoaderOfTemp = TempTestClass.class.getClassLoader();
        System.out.println(classLoaderOfTemp);
        System.out.println("看看TempTestClass是由哪个类加载器加载的---end");

        System.out.println("");
        System.out.println("");


        System.out.println("看看加载TempTestClass的加载器的类继承关系---begin");
        @SuppressWarnings("rawtypes")
        Class appClass = classLoaderOfTemp.getClass();
        while (appClass != null) {
            System.out.println(appClass);
            appClass = appClass.getSuperclass();
        }
        System.out.println("看看加载TempTestClass的加载器的类继承关系---end");

        System.out.println("");
        System.out.println("");


        System.out.println("看看加载TempTestClass的加载器的父类加载器的类继承关系---begin");
        @SuppressWarnings("rawtypes")
        Class extClass = classLoaderOfTemp.getParent().getClass();
        while (extClass != null) {
            System.out.println(extClass);

            extClass = extClass.getSuperclass();
        }
        System.out.println("看看加载TempTestClass的加载器的父类加载器的类继承关系---end");
    }
}

结果如下:

看看TempTestClass是由哪个类加载器加载的---begin
sun.misc.Launcher$AppClassLoader@65f4ba51
看看TempTestClass是由哪个类加载器加载的---end


看看加载TempTestClass的加载器的类继承关系---begin
    class sun.misc.Launcher$AppClassLoader
class java.net.URLClassLoader
class java.security.SecureClassLoader
class java.lang.ClassLoader
class java.lang.Object
看看加载TempTestClass的加载器的类继承关系---end


看看加载TempTestClass的加载器的父类加载器的类继承关系---begin
class sun.misc.Launcher$ExtClassLoader
class java.net.URLClassLoader
class java.security.SecureClassLoader
class java.lang.ClassLoader
class java.lang.Object
看看加载TempTestClass的加载器的父类加载器的类继承关系---end

有上面的输出结果便可知道结论了。


类加载器的委托机制


当一个类加载器加载类时,会把这个加载请求委托给父亲加载器,一直递归的委托上去。如果父亲没法加载,才会尝试自己加载,如下图:

这里写图片描述

之所以使用这种委托机制,是想保护JAVA核心库的类型安全,因为不同的加载器加载同一份字节码的时候,对于JVM来说,就是不同的类了,而且这些类还没法进行类型转换。设想一下,两个类加载器都加载了java.lang.Object到JVM中,那JVM中就有两份不同的java.lang.Object,而且它们之间是没法做类型转换的。

由此可以看到,虽然某个加载器触发了加载的动作,但是真正加载这个类是它的父类加载器。这里就有个说法,触发加载动作的类加载器叫初始类加载器,真正加载类的加载器叫做定义加载器。JVM判断一个类是否是同一个,会从两个方面来考虑,第一个是包名+类名是否相同,第二是加载这个类的类加载器是否相同,其中的类加载器指的就是定义加载器


参考的文章


1、深入探讨 Java 类加载器
2、Java深度历险(二)——Java类的加载、链接和初始化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值