专栏首页从流域到海域Java 类加载机制及双亲委派模型

Java 类加载机制及双亲委派模型

Java虚拟机类加载机制

虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类,这就是虚拟机的类加载机制。

在Java语言里面,类型加载、连接和初始化过程都是在程序运行期间完成。

类的整个生命周期:

即 加载 → \rightarrow →连接 → \rightarrow →初始化 → \rightarrow →使用 → \rightarrow →卸载 其中 连接包括:验证 → \rightarrow →准备 → \rightarrow →解析

类加载器

Java虚拟机团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制文件流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现上述动作的代码模块被称作“类加载器”。

对于任何一个类,都需要由加载它的类加载器和这个类来确立其在JVM中的唯一性。也就是说,两个类来源于同一个文件,并且被同一个类加载器加载,这两个类才相等。

双亲委派模型

从虚拟机的角度来讲,只存在两种不同的类加载器:(1)启动类加载器(Bootstrap ClassLoader),该类加载器使用C++语言来实现,属于虚拟机自身的一部分;(2)所有其他类加载器,这些类加载器是由Java语言实现的,独立于JVM外部,并且集成自抽象类java.lang.ClassLoader

从开发人员的角度来讲,大部分Java程序会使用到以下三种系统提供的类加载器。

  • 启动类加载器(Bootstrap ClassLoader):负责加载位于JAVA_HOME\lib目录中并且能被虚拟机识别的类库到JVM内存中。如果名称不符合的类库即使放在lib目录中也不会被加载。该类加载器无法被Java程序直接引用。
  • 扩展类加载器(Extension ClassLoader):该加载器主要是负责加载JAVA_HOME\lib\,该加载器可以被开发者直接使用。
  • 应用程序类加载器(Application ClassLoader):该类加载器也被称为系统类加载器,它负责加载用户类路径Classpath上所指定的类库,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

我们的应用程序都是由这三类加载器互相配合进行加载的。

  • 自定义类加载器(必须继承ClassLoader)

双亲委派模型

类加载器之间的层次关系,被称为类加载器的双亲委派模型(Parent Delegation Model),如下图:

双亲委派模型是在Java1.2之后引入的,其工作原理是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托该给父类的加载器去执行,如果父类加载器还存在器父类加载器,则继续向上委托,依次递归,请求最终将达到顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回;如果父类加载器无法完成此加载任务,子类加载器才会尝试自己去加载,这就是双亲委派模型。

双亲委派模型优势

Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层次关系可以避免类的重复加载,当父类已经加载了该类的时,就没有必要子类再加载一次。其次是安全因素,我们可以自定义一个Object类放到Classpath下,但由于默认存放在rt.jar内的java.lang.Object所对应的启动类加载器在双亲委派模型中处于顶层,其优先级最高,程序中所有的Object都是使用启动类加载器加载的java.lang.Object而不是我们自定义的Object,这在一定程度上保证了基础类得到统一,不会出现安全性问题。

双亲委派模型对于保证Java程序的稳定运作非常重要,但是其实现却非常简单。JDK中实现双亲委派模型的代码都集中在java.lang.ClassLoader中的loadClass()方法。

protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
	synchronized (getClassLoadingLock(name)) {
		Class<?> c = findLoadedClass(name);
		if(c == null) {
			try {
				if(parend != null) {
					c = parent.loadClass(name, false);
				} else {
					c = findBoostrapClassOrNull(name);
				}
			} catch (ClassNotFoundException e) {
                  // ClassNotFoundException thrown if class not found
                  // from the non-null parent class loader
			}
			if(c == null) {
				  // If still not found, then invoke findClass in order
                  // to find the class.
			}
		}
		if(resolve) {
			resolveClasss(c);
		}
		return c;
	}
}

其工作过程可以分为两步:

  1. 首先自底向上检查类是否被加载过(Class<?> c = findLoadedClass)
  2. 如果没有被加载过,那么就自顶向下尝试加载该类。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python 迭代(iteration)

    对一组数据进行遍历访问称为迭代(iteration)。 迭代是Python高级特性之一,而且Python的迭代比其他语言更为简便。但是请注意,迭代操作...

    Steve Wang
  • Exploration and Exploitation - 探索和利用

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

    Steve Wang
  • 偏差、方差和数据不匹配

    Human-level指人类在目标问题上的error,比如人眼识别猫,人会识别错的error。

    Steve Wang
  • Tomcat 类加载器打破双亲委派模型

    1. 什么是类加载机制? 2. 什么是双亲委任模型? 3. 如何破坏双亲委任模型? 4. Tomcat 的类加载器是怎么设计的?

    爱撸猫的杰
  • JVM真香系列:轻松理解class文件到虚拟机(下)

    上面我们自定义一个String出了问题,问题在于JVM不知道我们想用哪个类,于是JVM就定义了个规范。

    田维常
  • 今天来聊Java ClassLoader

    类加载机制作为一个高频的面试题经常会在面试中被问到,前几天一个电话面试就问到,之前有了解过,但是没有梳理成自己的体系,所以说的有点凌乱,今天花点时间整理一下,分...

    纯洁的微笑
  • Java类加载机制

    答:当某个类加载器在接到加载类的请求时,会将加载任务委托给父类加载器,依次递归,父类加载器可以完成类加载任务,就成功返回;不能加载则子类加载器自己完成加载。有3...

    宇宙之一粟
  • JVM学习第三天(JVM的执行子系统)之类加载机制补充

    对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。这句话可以表达得更通俗一些...

    彼岸舞
  • 浅谈Java类加载器

    注意最后的null值应该是启动类加载器、单因为是C++语言编写的,所以无法获取到相关的信息

    Java学习录
  • JVM类加载器三问—虾皮真题

    我们编写的java文件会在编译后变成.class文件,类加载器就是负责加载class字节码文件,class文件在文件开头有特定的文件标识,将class文件字节码...

    码上积木

扫码关注云+社区

领取腾讯云代金券