欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

深入JVM原理之类加载 - 双亲委派模型

程序员文章站 2022-04-14 23:18:35
...
一、类加载机制
  • 类加载机制:虚拟机把描述类的数据从.class文件加载到内存中,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。

  • 类加载的过程:深入JVM原理之类加载 - 双亲委派模型

    (1) 加载:将class文件字节码内容加载到内存中;并将这些内容转换成方法区中的运行时数据结构;在内存中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口在方法区中分配
    (2) 验证:确保class 文件中的字节内容符合jvm规范,并且不会危害jvm自身的安全
    (3) 准备:正式为类变量(静态变量)分配内存空间,并为静态变量初始化(赋默认值),静态变量的内存
    (4) 解析:虚拟机常量池内的符号引用替换为直接引用的过程,比如String s =“aaa”,转化为 s的地址指向“aaa”的地址
    (5) 初始化:根据程序员通过程序制定的主观计划完成静态变量等资源的初始化。在这个过程会完成静态变量的赋值和静态代码块中的语句

二、类加载器(ClassLoader)
  • 类加载器:用于实现类加载过程中加载阶段,负责将class文件字节码内容加载到内存中;并将这些内容转换成方法区中的运行时数据结构,在内存中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口。深入JVM原理之类加载 - 双亲委派模型

  • 类加载器的分类:

    (1) 虚拟机自带的类加载
          a. 启动类加载器:C++语言实现,负责加载 %Java_home%/jre/lib/rt.jar 中的内容
          b. 扩展类加载器:Java语言实现,负责加载%Java_home%/jre/lib/ext/*.jar中的内容
          c. 应用程序类加载器:也可以称为系统类加载器,它负责加载用户类路径classPath的所有类。
          注意:如果应用程序中没有定义过自己的类加载器,一般情况默认使用应用程序类加载
    (2) 用户自定义的类加载器:
          a. 用户可以自定义类加载器,继承java.lang.ClassLoader
    深入JVM原理之类加载 - 双亲委派模型

  • 类加载器的双亲委派模型(Parents Delegation Model):

    工作过程:如果一个类加载器收到了加载请求,它首先不会尝试使用自己加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到最顶层的启动类加载中,只有父类反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需要的类)的时候,子类才会尝试自己加载。

    好处:采用双亲委派模型组织累加器之间的关系,有一个显而易见的好处是Java随着它的类加载一起具备了一种带有优先级的层次关系,例如加载位于rt.jar中的java.lang.Object类,无论哪一个类加载加载这个类,最终都委托给最*的启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。

  • 示例代码:

    public class Test{
    	public static void main(String[] args) throws IOException {
     	
    	 	Object obj = new Object();
    	 	System.out.println(obj.getClass().getClassLoader());
    	 	
    	 	MyClass mc = new MyClass();
    	 	System.out.println(mc.getClass().getClassLoader().
                            getParent().getParent());
    	 	System.out.println(mc.getClass().getClassLoader().getParent());
    	 	System.out.println(mc.getClass().getClassLoader());		
     	}class MyClass{}
    
  • 类加载器底层分析:

    双亲委派模型对于java正常运作很重要,但是底层实现非常简单,实现双亲委派的大代码集中在java.lang.ClassLoader的loadClass()方法中:先检查是否已经被加载过,若没有加载则调用父类的loadClass方法,直到找到启动类加载,启动类加载器在在自己的范围内进行搜素,如果父类加载器加载失败,则子类处理异常,调用自身的findClass方法进行加载。

    protected synchronized Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException {
    	// First, check if the class has already been loaded
    	Class c = findLoadedClass(name);
    	if (c == null) {
    	    try {
    		if (parent != null) {
    		    c = parent.loadClass(name, false);
    		} else {
    		    c = findBootstrapClass0(name);
    		}
    	    } catch (ClassNotFoundException e) {
    	        // If still not found, then invoke findClass in order
    	        // to find the class.
    	        c = findClass(name);
    	    }
    	}
    	if (resolve) {
    	    resolveClass(c);
    	}
    	return c;private Class findBootstrapClass0(String name)
    throws ClassNotFoundException{
    	check();
    	if (!checkName(name))
    	    throw new ClassNotFoundException(name);
    	return findBootstrapClass(name);private native Class findBootstrapClass(String name)throws ClassNotFoundException;