常见面试题-双亲委派模型

双亲委派模型

class 文件是通过 类加载器 装在到 JVM 中的,为了防止内存中存在多份同样的字节码,使用了双亲委派模型

双亲委派模型对于保证 Java 程序的稳定运行至关重要

双亲委派模型的原理为:

(1)如果一个类加载器收到了类加载请求,会先将请求委托给父类的加载器去执行

(2)如果父类加载器还存在父类,则继续向上委托,直至到达顶层的引导类加载器

(3)如果父类加载器可以完成类加载,就返回;否则,子类加载器才会尝试自己去加载

双亲委派模型演示:

  1. 创建一个java.lang包,包下创建一个String类
  2. 我们来测试创建String对象的时候加载的是系统的String类,还是我们创建的String类

常见面试题-双亲委派模型_第1张图片

package java.lang;

// 自己创建的java.lang.String类
public class String {
   static {
      System.out.println("我是自己创建的String类中的静态代码块!");
   }
}

package com.qy;

// 测试类
public class StringTest {
   public static void main(String[] args) {
      String str = new String();
      /**
      测试结果:并没有输出,说明加载的是系统中的String类,而不是自定义的
      */
   }
}

那么为什么加载的不是自定义的String类呢?

根据双亲委派的工作原理,加载 String 类的时候,系统类加载器收到了类加载的请求,会向上委托给扩展类加载器,扩展类加载器会再向上委托给引导类加载器引导类加载器会加载java包下的类,因此 String 类由引导类加载器加载,所以不会加载自定义的 String 类。

如果需要加载 StringTest 类的话,会一直向上委派到引导类加载器,但是该加载器并不加载 StringTest 类,所以最终仍然由系统类加载器完成对 StringTest 类的加载。

使用双亲委派模型的优势是什么呢?

  • 避免类的重复加载
  • 可以保护程序安全,防止核心 API 被随意篡改(如上例中我们自定义 java.lang.String 类,如果没有双亲委派机制,导致加载了我们自定义的 String 类,会导致程序不安全)

扩展:类加载器的分类

虚拟机默认提供了 3 个类加载器,为:引导类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)、应用程序类加载器(Application ClassLoader)

除了这三种类加载器之外,还有一种用户自定义类加载器(User Defined ClassLoader)

常见面试题-双亲委派模型_第2张图片

查看类加载器层级关系:

public class ClassLoaderTest {
   public static void main(String[] args) {

      // 获取系统类加载器
      ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
      System.out.println(systemClassLoader); // sun.misc.Launcher$AppClassLoader@18b4aac2

      // 获取其上层:扩展类加载器
      ClassLoader extClassLoader = systemClassLoader.getParent();
      System.out.println(extClassLoader); // sun.misc.Launcher$ExtClassLoader@1b6d3586

      // 获取其上层:获取不到引导类加载器
      ClassLoader bootstrapClassLoader = extClassLoader.getParent();
      System.out.println(bootstrapClassLoader); // null

      // 对于用户自定义类来说:默认使用系统类加载器进行加载
      ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
      System.out.println(classLoader); // sun.misc.Launcher$AppClassLoader@18b4aac2

      // String类使用引导类加载器进行加载的 ---> java的核心类库都是使用引导类加载器进行加载的
      ClassLoader classLoader1 = String.class.getClassLoader();
      System.out.println(classLoader1); // null
   }
}

你可能感兴趣的:(面试题,java,面试,jvm)