类加载器及其双亲委托机制

类加载器分为4种:

1.根类(Bootstrap)加载器

启动类加载器主要加载的是JVM自身需要的类,这个类加载使用C++语言实现的,不开源,是虚拟机自身的一部分,它负责将 <JAVA_HOME>/lib路径下的核心类库或-Xbootclasspath参数指定的路径下的jar包加载到内存中

2.扩展类(Extension)加载器

扩展类加载器是指Sun公司(已被Oracle收购)实现的sun.misc.Launcher$ExtClassLoader类,由Java语言实现的,是Launcher的静态内部类,它负责加载<JAVA_HOME>/lib/ext目录下或者由系统变量-Djava.ext.dir指定位路径中的类库

扩展类加载器加载类是加载以jar包形式存在的class的,单独的class文件不加载

3.应用类/系统类(System)加载器

也称应用程序加载器是指 Sun公司实现的sun.misc.Launcher$AppClassLoader。它负责加载系统类路径java -classpath或-D java.class.path 指定路径下的类库,也就是我们经常用到的classpath路径,开发者可以直接使用系统类加载器,一般情况下该类加载是程序中默认的类加载器,通过ClassLoader#getSystemClassLoader()方法可以获取到该类加载器。

4.自定义类加载器。


双亲委托机制



如上图所示,如果要加载Sample类,加载过程为:

1.向自定义类加载器loader1发起申请加载,loader1委托给系统类加载器,系统类加载器委托给扩展类加载器,扩展类加载器委托给根类加载器

2.根类加载器加载失败,返回给扩展类加载器;

3.扩展类加载器加载失败,返回给系统类加载器

4.系统类加载成功,返回给loader1


举例说明:

1.如java.lang.String等jdk自带的类,他们的类加载器是Bootstrap加载器

2.引入外部jar包的类/非核心的jdk类,他们的类加载器是扩展类(Extension)加载器

3.我们业务自定义的类,类加载器是应用类/系统类(System)加载器

注意的一点,jvm提供了方法改变默认的系统类加载器,用户可以通过修改property:java.system.class.loader这个配置改变默认的系统类加载器

4.数组类型的加载是在jvm运行期动态进行的,数组类型的加载器跟里面元素的加载器一致,如String[]的加载器是Bootstrap加载器,业务自定义类数组的加载器是应用类/系统类(System)加载器。如果数组的类型是原生类型,则此数组类没有加载器(注意:数组类型加载不是类加载器完成的,是jvm运行时动态加载的)



ps:

父加载器加载的类不能使用子加载器加载的类的任何信息,子加载器加载的类可以使用父加载器的内容

例如:我们可以在我们自定义的类里使用String类,但是不能在String类里使用我们自定义的类


如果一个类A里面要加载类B(例如在类A创建类B的实例),会使用加载类A的加载器来加载类B(但是还是会使用双亲委托机制)


类加载器双亲委托模型的好处:

1.可以确保java核心库的类型安全:所有的java应用都至少会引用java.lang.Object类,也就是说,java.lang.Object这个类会被加载到JVM中,如果这个加载过程是由JAVA应用自己的类加载器加载的,那么就可能会在JVM中存在多个版本的java.lang.Object这个类,而且这些类之间,是不兼容的,是互不可见的(正是命名空间在发挥作用 )

借助于双亲委托机制,java的核心类库都是由根类加载器来加载完成,从而确保了java应用所使用的都是同一个版本的java核心类库,他们是互相兼容的

2.可以确保java核心类库所提供的类不会被自定义的类所替换

3.不同的类加载器可以为相同名称(binary name)的类创建额外的命名空间,相同名称的类可以并存在jvm中,只需要用不同的类加载器来加载它们即可,不同类加载器所加载的类之间是不兼容的,这就相当于在jvm内部创建了又一个相互隔离类空间,这类技术在很多框架中都得到了实际的应用


在运行期,一个java类是由该类的完全限定名(binary name,二进制名)和用于加载该类的定义类加载器(defining loader)所共同决定的

如果同样名字的类(即由相同的完全限定名)是由两个不同的加载器加载的,那么这些类是不同的,即便是.class文件完全一样,并且也是从相同的地方加载,亦如此


当前类加载器(Current Classloader):

每个类都会使用自己的类加载器(即加载自身的类加载器)来去加载其他的类(指的是所依赖的类)

如果ClassX引用了ClassY,那么ClassX的类加载器,就会尝试加载ClassY(前提是ClassY没被加载的情况下)


猜你喜欢

转载自blog.csdn.net/mweibiao/article/details/79897267