深入理解java类加载器以及双亲委派模型

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_43847987/article/details/101100014

类加载器的任务是根据一个类的全限定名来读取此类的二进制字节流到JVM中,然后转换为一个与目标对应的java.lang.Class对象实例

虚拟机的角度来看,有两种类加载器:

  • 启动类加载器:这个类加载器使用C++语言实现,是虚拟机的一部分
  • 所有其他的类加载器:这些类都是由Java语言实现,独立于虚拟机外部,并且全都继承于java.lang.ClassLoader

从java开发人员的角度来看,有三种类加载器:

  • 启动类加载器:负责将存放在<JAVA_HOME>\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机所识别的(仅按照文件名识别)类库加载到虚拟机内存中。
  • 扩展类加载器:这个加载器由sun.misc.Launcher$ExtClassLoader实现,负责加载<JAVA_HOME>\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器
  • 应用程序类加载器:这个类由sun.misc.launcher$AppClassLoader实现,负责加载用户类路径上所指定的类库,开发者可以直接使用这个类加载器。

应用程序都是由这三种类加载器互相配合加载的,当然我们也可以自定义类加载器。java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将他的class文件加载到内存生成class对象,而且加载某个类的class文件时,java虚拟机采用的是双亲委派模式即把请求交由父类处理,它是一种任务委派模式。

双亲委派模型
双亲委派模型的工作过程:如果一个类接收到了类加载的请求,他首先把这个请求委托给他的父类加载器去完成,每个层次的类加载器都是这样,因此所有的加载请求都应该传送到顶层的启动类加载器种,只有当父加载器反馈自己无法完成这个请求时(它的搜索范围没有找到所需的类),子加载器才会尝试自己去加载。

使用双亲委派模型加载的好处:java类随着它的类加载器一起具备了一种带有优先级的层次关系。通过这种层级关系可以避免类的重复加载。例如类java.lang.Object,他存放在rt.jar中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型顶层的启动类加载器来进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。
双亲委派模型对于保证java程序的稳定运作很重要,实现却很简单,实现代码如下:

protected synchronized Class<?> loadClass(String name,boolean resolve) throws ClassNotFoundException{
//首先判断该类型是否已经被加载
		Class c=findLoadedClass(name);
		if(c==null){
		//如果没有被加载,就委托父类加载或者给启动类加载器加载
			try{
					if(parent!=null){
					//如果存在父类加载器,就委派父类加载器加载
							c=parent.loadClass(name,false);
					} else {
					//如果不存在父类加载器,就检查是否是由启动类加载器加载的类,通过调用本地方法native Class
							c=findBootstrapClassOrNull(name);
					}
				}catch(ClassNotFoundException e){
				//如果父类加载和启动类加载都不能完成任务,才调用自身的功能,一般自定义加载器重写此方法
					c=findCass(name);
				}
			}
		if(resolve){//是否初始化
					resolveClass(c);
	}
		return c;
}

猜你喜欢

转载自blog.csdn.net/weixin_43847987/article/details/101100014
今日推荐