专注Java教育14年 全国咨询/投诉热线:444-1124-454
星辉LOGO图
始于2009,口口相传的Java黄埔军校
首页 学习攻略 职业指南 比较代表性的jvm加载器面试题及答案

比较代表性的jvm加载器面试题及答案

更新时间:2023-02-03 11:23:09 来源:星辉 浏览779次

Java编程最大的特点就是与平台的无关性,使用Java虚拟机来实现这一点是最关键的,所以我们在面试相关岗位的时候,JVM的相关面试题经常被问到,今天小编就总结了一些比较有代表性的问题,希望可以在就业上给予大家一些帮助:

jvm加载器面试题及答案

1、Class.forName 和 ClassLoader.loadClass 都能加载类,这两者在加载类时的区别?

  • Class.forName有重载方法可以指定是否需要初始化,而默认的方法初始化设置为true这会初始化类执行链接和初始化操作
  • ClasaLoader是有类加载器的loadClass方法加载,传入的是false,只会执行连接操作,不会初始化操作

Class.forName()方法实际上也是调用的CLassLoader来实现的。

Class.forName(String className);这个方法的源码是:

@CallerSensitive public static Class forName(String className) throws ClassNotFoundException { Class caller = Reflection.getCallerClass(); return forName0(className, true, ClassLoader.getClassLoader(caller), caller); }

最后调用的方法是forName0这个方法,在这个forName0方法中的第二个参数被默认设置为了true,这个参数代表是否对加载的类进行初始化,设置为true时会类进行初始化,代表会执行类中的静态代码块,以及对静态变量的赋值等操作。Class.forName加载类是将类进了初始化,而ClassLoader的loadClass并没有对类进行初始化,只是把类加载到了虚拟机中

2、什么叫类加载器

虚拟机把描述类的数据文件(字节码)加载到内存,并对数据进行验证、准备、解析以及类初始化,最终形成可以被虚拟机直接使用的java类型(java.lang.Class对象)。

3、类的生命周期

加载过程:通过一个类的全限定名来获取定义此类的二进制字节流,将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。在内存中(方法区)生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口;

找到类文件(通过类的全限定名来获取定义此类的二进制字节流)

放入方法区(将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构)

开个入口(生成一个代表此类的java.lang.Class对象,作为访问方法区这些数据结构的入口)

验证过程:为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,文件格式验证、元数据验证、字节码验证、符号引用验证

准备过程:正式为类属性分配内存并设置类属性初始值的阶段,这些内存都将在方法区中进行分配

解析阶段:虚拟机将常量池内的符号引用替换为直接引用的过程

初始化阶段:类初始化阶段是类加载过程的最后一步。初始化阶段就是执行类构造器()方法的过程

使用阶段:

卸载阶段:

4、类加载器

类加载器负责加载所有的类,同一个类(一个类用其全限定类名(包名加类名)标志)只会被加载一次。

  1. Bootstrap ClassLoader:根类加载器,负责加载java的核心类,它不是java.lang.ClassLoader的子类,而是由JVM自身实现
  2. Extension ClassLoader:扩展类加载器,扩展类加载器的加载路径是JDK目录下jre/lib/ext,扩展类的getParent()方法返回null,实际上扩展类加载器的父类加载器是根加载器,只是根加载器并不是Java实现的
  3. Application ClassLoader:应用程序类加载器,它负责在JVM启动时加载来自java命令的-classpath选项、java.class.path系统属性或CLASSPATH环境变量所指定的jar包和类路径。程序可以通过getSystemClassLoader()来获取系统类加载器。系统加载器的加载路径是程序运行的当前路径。

双亲委派模型的工作过程

  1. 先查找当前ClassLoader是否加载过此类,有就返回;
  2. 如果没有,查询父ClassLoader是否已经加载过此类,如果已经加载过,就直接返回Parent加载的类;
  3. 如果整个类加载器体系上的ClassLoader都没有加载过,才由当前ClassLoader加载(调用findClass),整个过程类似循环链表一样。

双亲委托机制的作用

  1. 共享功能:可以避免重复加载,当父亲已经加载了该类的时候,子类不需要再次加载,一些Framework层级的类一旦被顶层的ClassLoader加载过就缓存在内存里面,以后任何地方用到都不需要重新加载。
  2. 隔离功能:java核心类库的纯净和安全,防止恶意加载。

如何打破双亲委派模型?

  1. 双亲委派模型的逻辑都在loadClass()中,重写loaderClass()、findClass()
  2. 系统自带的三个类加载器都加载特定目录下的类,如果我们自己的类加载器放在一个特殊的目录,那么系统的加载器就无法加载,也就是最终还是由我们自己的加载器加载

打破双亲委派

“双亲委派”机制只是Java推荐的机制,并不是强制的机制。

比如JDBC就打破了双亲委派机制。它通过Thread.currentThread().getContextClassLoader()得到线程上下文加载器来加载Driver实现类,从而打破了双亲委派机制。

自定义ClassLoader

  1. loadClass(String name,boolean resolve):根据指定的二进制名称加载类
  2. findClass(String name): 根据二进制名称来查找类
  3. 直接使用或继承已有的ClassLoader实现:java.net.URLClassLoader、java.security.SecureClassLoader、 java.rmi.server.RMIClassLoader
  4. 在调用loadClass(),会先根据委派模型在父加载器中加载,如果加载失败,则会调用自己的findClass方法来完成加载

5、引起类加载操作的五个行为

遇到new、getstatic、putstatic或invokestatic这四条字节码指令

反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化

子类初始化的时候,如果其父类还没初始化,则需先触发其父类的初始化

虚拟机执行主类的时候(有 main(string[] args))

JDK1.7 动态语言支持

以上就是“比较代表性的jvm加载器面试题及答案”,你能回答上来吗?如果想要了解更多的Java面试题相关内容,可以关注星辉Java官网。

提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>