JVM-类加载器与双亲委托

虚拟机为HotSpot

1.类加载器
类加载器一般只有3种(除开自己定义的)分别为:

1.Bootstrap ClassLoader:根加载器

2.Extension ClassLoader:扩展加载器

3.System ClassLoader:系统加载器

以下我们将对这3种加载器进行分析:

1.Bootstrap ClassLoader 根加载器
Bootstrap ClassLoader(根加载器)是由C++编写的加载器,负责加载

<JAVA_HOME>/lib文件夹下的类,或者被-Xbootclasspath参数指定的路径.

代码:打印被跟加载器加载的类

public class Test01 {
    public static void main(String[] args) {
        for (URL url : sun.misc.Launcher.getBootstrapClassPath().getURLs()) {
            // 遍历、输出根类加载器加载的全部URL
            System.out.println(url.toExternalForm());
        }
    }
}
结果:

file:/C:/Program%20Files/Java/jdk1.8.0_202/jre/lib/resources.jar
file:/C:/Program%20Files/Java/jdk1.8.0_202/jre/lib/rt.jar
file:/C:/Program%20Files/Java/jdk1.8.0_202/jre/lib/sunrsasign.jar
file:/C:/Program%20Files/Java/jdk1.8.0_202/jre/lib/jsse.jar
file:/C:/Program%20Files/Java/jdk1.8.0_202/jre/lib/jce.jar
file:/C:/Program%20Files/Java/jdk1.8.0_202/jre/lib/charsets.jar
file:/C:/Program%20Files/Java/jdk1.8.0_202/jre/lib/jfr.jar

可以看出Bootstrap ClassLoader加载的文件全部都位于lib包下.

2.Extension ClassLoader 扩展加载器
Extension ClassLoader 扩展加载器由sun.misc.Launcher$ExtClassLoader实现,主要负责加载<JAVA_HOME>/lib/ext目录下的文件,或者java.ext.dirs指定的库.

代码:

public class Test02 {
    public static void main(String[] args) throws ClassNotFoundException {
        //注:这个类位于ext目录下localedata.jar包
        Class<?> aClass = Class.forName("sun.util.resources.ar.CalendarData_ar");
        ClassLoader loader = aClass.getClassLoader();
        System.out.println(loader);
    }
}

结果:

sun.misc.Launcher$ExtClassLoader@74a14482
1
可以看出打印的类加载为ExtClassLoader.

3.System ClassLoader 系统加载器(应用程序类加载器)
System ClassLoader 系统加载器由sun.misc.Launcher$AppClassLoader实现,主要加载用户指定的classpath下的类(工程项目的classpath下的类).

代码:

public class Test03 {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取本类的加载器
        Class clazz = Class.forName("com.test.ClassLoader.Test03");
        System.out.println(clazz.getClassLoader());
    }
}

结果:

sun.misc.Launcher$AppClassLoader@18b4aac2
1
2.双亲委托


上图显示加载器之间的层次关系,除了根加载器没有父类以外,每个加载器必须有自己的父类.

代码:

public class Test04 {
    public static void main(String[] args) throws ClassNotFoundException {
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println("子类"+systemClassLoader);
        ClassLoader parent1 = systemClassLoader.getParent();
        System.out.println("系统加载器的父类"+parent1);
        ClassLoader parent2 = parent1.getParent();
        System.out.println("扩展加载器的父类"+parent2);
    }
}

结果:

子类sun.misc.Launcher$AppClassLoader@18b4aac2
系统加载器的父类sun.misc.Launcher$ExtClassLoader@1b6d3586
扩展加载器的父类null
其中,我们可以看见,扩展加载器的父类为null,为什么,在ClassLoader的源码中有这样的一句话.

/**
     * Returns the parent class loader for delegation. Some implementations may
     * use <tt>null</tt> to represent the bootstrap class loader. This method
     * will return <tt>null</tt> in such implementations if this class loader's
     * parent is the bootstrap class loader.
**/     
大概意思就是当返回bootstrap时,用null代替,所以可以解释为什么扩展类加载器的父类为null.

双亲委托

假设我们的自定义类加载器的父类为系统类加载器,当自定义加载器接收到需要加载类的命令时,他并不会开始加载类,而是去寻找自己的父类,让父类去加载,但是,当父类接收到时,他也会重复这一步,去寻找他自己的父类,直到根加载器,如果这时,根加载器可以加载,他将加载,无法加载,他的子类才会开始尝试加载,其中有一个子类加载成功就退出,所有子类都无法加载成功,就会报错.

如果我们自己创建一个java.lang.Integr包,使用类加载器去加载,在双亲委托机制下,他将永远不会加载成功,应为他会从根类开始加载,Integer包位于rt.jar中,将由Bootstrap ClassLoader加载,当加载自己的Integr包时,他会发现包已存在,从而导致加载失败,不过,这样也保证了系统的稳定运行,不然就会出现多个名字相同的Integer包,造成系统混乱.防止恶意篡改系统API.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值