我的面试经之JVM(二)类加载器的分类
·JVM支持两种类型的类加载器:分别为引导类加载器(Bootstrap ClassLoader)和自定义类加载器(User-Defined ClassLoader)
·从概念上来讲,自定义类加载器一般指开发人员自定义类的加载器,但是JVM规范是将所有派生于抽像类ClassLoader的类加载器都是自定义类加载器
·不论加载器类型如何划分,在程序中我们最常见的只有三个:引导类加载器、扩展类加载器·、系统类加载器
这四者是包含关系不是上下层关系,也不是继承关系。
只有BootStrap是C和C++写的,其他的是Java语言写的
扩展类加载器和系统类加载器都间接继承ClassLoader
实例图:
结论: 系统类加载器的上层是扩展类加载器,扩展类加载器的上层是引导类加载器
Java核心类库用引导类加载器加载,用户自定义类加载器,默认使用系统类加载器。
启动类加载器(引导类加载器Bootstrap ClassLoader):
由C/C++实现,嵌套在JVM内部
用来加载Java的核心库(JAVA_ HOME/jre/lib/rt.jar、resources . jar或sun . boot . class. path路径下的内容) , 用于提供JVM自身需要的类
并不继承自java.lang.ClassLoader,没有父类加载器
加载扩展类和应用程序类加载器,并指定为他们的父类加载器
出于安全考虑BootStrap只加载包名为java、javax、sun开头的类
结果:
扩展类加载器(Extension ClassLoader)
Java语言编写,由sun.misc.Launcher$ExtClassLoader内部类实现
派生于ClassLoader类
父类加载器为启动类加载器
从java. ext .dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录(扩展目录)下加载类库。如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载。
结果:
应用程序类加载器(系统类加载器 AppClassLoader)
Java语言编写,由sun.misc.Launcher$ExtClassLoader内部类实现
派生于ClassLoader类
父类加载器为扩展类加载器
负责从环境变量classpath或系统属性 java.class.path指定路径下的类库
该类是程序中默认的类加载器,一般来说,Java应用的类都由它完成
通过ClassLoader #getSystemClassLoader ()方法可以获取到该类加载器
用户自定义类加载器
在Java的日常应用程序开发中,类的加载几乎是由上述3种类加载器相互配合执行的,在必要时,我们还可以自定义类加载器,来定制类的加载方式。
为什么要有用户自定义类加载器
隔离加载器类(用到中间件)
修改类加载的方式
扩展加载源
防止源码泄露
用户自定义类加载器实现步骤
1.开发人员可以通过继承抽象类java. lang.ClassLoader类的方式,实现自己的类加载器,以满足一些特殊的需求
2.在JDK1.2之前,在自定义类加载器时,总会去继承ClassLoader类并重写loadClass()方法,从而实现自定义的类加载类,但是在JDK1.2之后已不再建议用户去覆盖loadClass()方法,
而是建议把自定义的类加载逻辑写在findClass()方法中
3.在编写自定义类加载器时,如果没有太过于复杂的需求,可以直接继承URLClassLoader类,这样就可以避免自己去编写findClass()方法及其获取字节码流的方式,
使自定义类加载器编写更加简洁。