java类加载机制ClassLoader与双亲委托

Java程序不是一个可执行程序,而是由许多独立的类文件组成的,每一个文件对应一个java类,并且运行时这些类文件不是全部装入内存的,而是根据程序得需要逐渐载入,ClassLoader就是类加载器,作用是将.class文件装载到jvm中。ClassLoader是JVM实现得一部分,当虚拟机运行时加载java核心得API。

一.java类的装载方式

1.隐式装载:程序运行过程中遇到new方式生成的对象时,隐式调用类装载器加载对应的类到jvm中

2.显示装载:通过class.forname()方法,显示装载需要的类

二.类装载器分类介绍

1.Bootstrap ClassLoader:最顶层的加载类,主要加载核心类库

   %JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等;

2.Extention ClassLoader:扩展的类加载器,主要加载%JRE_HOME%\lib\ext下的jar包和class文件;

3.Appclass Loader:也称为SystemAppClass,加载当前应用的classpath的所有类;

BootStrap loader加载完ExtClassLoader后就会加载AppClassLoader,并且将AppClassLoader的父类加载器指定为 

ExtClassLoader

                                             

三.测试代码

public class ClassLoaderTest{
    public static void main(String args[]){
        System.out.println(ClassLoaderTest.class.getClassLoader());
        ClassLoader load = ClassLoaderTest.class.getClassLoader();
        ClassLoader load1 = load.getParent();
        System.out.println(load1);
        ClassLoader load2 = load1.getParent();
        System.out.println(load2);
    }
}

输出:

sun.misc.Launcher$AppClassLoader@73d16e93
sun.misc.Launcher$ExtClassLoader@15db9742
null

说明了ClassLoaderTest是通过AppClassLoader加载的,AppClassLoader的父加载器是ExtClassLoader

但是ExtClassLoader的父加载器是空的是因为BootstrapLoader是由C++写的,在java的观点上,逻辑上并不存在BootstrapLoader的类实体,所以输出内容为null;

四.双亲委托

JVM加载一个class的时候会先查看这个类是否加载过,如果没有加载过则通过父加载器,然后递归下去知道BootstrapLoader如果Bootstraploader找到了就直接返回,如果没有找到则一级一级的返回,最后到达自身取查找这些对象,这种机制叫做双亲委托。

使用这种机制的好处是可以避免重复加载,如果父加载器已经加载了该类的时候就没有必要子加载器重新加载

另一方面也考虑到了安全因素,如果不使用委托模式,就可以随时使用定义的String来动态代替java核心api中定义的类,这样存在非常大的安全隐患,父类委托方式可以避免这种情况,因为String已经在启动时被加载,所以用户自定义类是无法加载一个自定义的ClassLoader。

protected synchronized Class loadClass(String name ,boolean reslove)
throws ClassNotFoundException
{
//首先检查该name制定的class是否有被加载
Class c = findLoadedClass(name);
if(c == null){
try{
if(parent != null){
//如果parent不为null,则调用parent的loadClass进行加载
c = parent.loadClass(name,false);
}else{
//parent为null则调用BootstarpClassLoader进行加载
c = findBootstrapClass0(name);
}
}catch(ClassNotFoundException e){
//如果仍无法加载成功,则调用自身的findClass进行加载
c = findClass(name);
}
}
if(resolve){
resloeClass(c);
}
return c;
}

五.一些重要的方法

1.loadClass方法

ClassLoader.loadClass()是ClassLoader的入口点,定义如下:

calss loadClass(String name,boolean reslove)

name是指JVM需要的类的名称,如java.lang.Object,relove参数告诉方法是否需要解析类,在准备执行类之前,需要考虑类解析,(如果JVM找到该类的超类则不需要解析)

2.defineClass方法

defineClass方法接受由原始字节组成的数组,并把它转换成class对象,原始数组包含如从文件按系统或网络装入的数据,defineClass管理JVM的许多复杂的实现层面,因为defineClass方法被标记成final的所以不能覆盖它

3.findSystemClass方法

findSystemClass方法从本地文件系统装入文件,他在本地文件系统中寻找类文件,如果存在,就使用defineClass原始字节转换成Class对象,以将该文件转换成类,

4.resolveClass方法

自己编写loadClass的时候可以调用resolveClass

5.findLoadedClass方法

findLoadedClass充当一个缓存:当请求loadClass装入类时,它调用该方法来查看ClassLoader是否已经装入这个类,这样可以避免重新装入已经存在的类造成麻烦

6.findClass方法

loadClass默认实现调用这个新方法,findClass的用途包含ClassLoader的所有特殊代码,而无需复制其他代码

7.forName方法

class类中有一个静态方法forName,这个方法和ClassLoader中的LoadClass方法目的一样 都是用来加载class的

参考文章:https://www.jianshu.com/p/1f5baa2947d2

参考书:《JAVA程序员面试宝典》

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值