您的位置 首页 java

Java面试篇基础部分-Java的类加载机制

JVM的类加载

JVM在运行Java文件的时候,类加载分为5个阶段:加载、验证、准备、解析、初始化。在类初始化加载完成之后,就可以使用这个类的信息了。当这个类不需要使用的时候,就可以从JVM进行卸载。

Java面试篇基础部分-Java的类加载机制

加载

加载是指JVM读取Class文件的操作,并且根据Class的文件描述创建对应的java.lang.Class对象的过程。我们知道在Java中可以通过Class.forName()的方式进行反射操作。类加载过程中包含将Class文件读取到运行时区域的方法内,并且在堆内存中创建java.lang.Class对象,并封装类在方法区的数据结构的过程。在读取Class文件的时候可以通过文件的形式进行读取,也可以通过jar包或者是war的形式读取,还可以通过动态代理的方式自动生成Class或者通过其他的读取方式进行操作。

验证

主要是为了保证Class文件符合当前虚拟机的要求,保证虚拟机自身的安全,只有通过对应安全机制验证的Class文件才能被JVM顺利加载。

Java面试篇基础部分-Java的类加载机制

准备

主要的工作是在方法区中为类变量分配内存空间,并且设置类中的变量的初始化操作。初始值是指不同数据类型的默认值,需要注意的是final类型的变量和非final类型的变量在准备阶段的数据初始化过程不同。

 public static long value =1000;  

在上面代码中,静态变量value在准备阶段的初始值就是0,将value的值设置成1000的操作是在对象初始化完成的时候才进行设置的,因为Java中静态变量是随着类一起被创建的,所以在编译阶段会将静态变量的初始化操作定义在构造器中。

 public static final int value = 1000;  

如果是final变量,则JVM会在编译的时候生成对应的ConstantValue属性,虚拟机在准备阶段会根据ConstantValue的属性将value赋值为1000。

解析

将常量池中的符号引用替换为对应的直接引用。

初始化

主要是执行对应类的构造器方法<client>进行初始化操作,<client>方法是在编译的过程中有编译器自动收集类中的静态语句块和变量的赋值操作组成的。

JVM规定了,在初始化过程中父类的<client>方法执行完成之后,子类中的对应的<client>方法才会被执行。在一个类中如果没有任何的静态语句块或者静态变量赋值的时候,则不会生成对应的<client>方法。

出现下面几种情况的时候JVM不会执行类的初始化流程。

  • 常量在编译的时候会将其对应的值放入到常量池中,在该过程中不需要调用常量池所在的类,所以不会触发常量类的初始化操作。
  • 在子类引用父类的静态字段的时候,不会触发子类的初始化操作,只会触发父类的初始化操作。
  • 定义对象数组,不会触发该类的初始化操作。
  • 在使用类名获取Class对象的时候不会触发初始化操作。
  • 在使用Class.forName加载指定的类的时候,可以通过initialize参数设置是否需要对类进行初始化操作。
  • 在使用ClassLoader默认的loadClass方法的时候不会触发该类的初始化操作。

类加载器

JVM提供了三种类加载器

  • 引导类加载器
  • 扩展类加载器
  • 程序应用类加载器
Java面试篇基础部分-Java的类加载机制

(1)启动类加载器:负责加载的是JAVA_HOME的lib目录下的类,通过-Xbootclasspath参数指定路径中被JVM认可的类库

(2)扩展类加载器:负责加载JAVA_HOME下的lib/ext目录中的类库,通过java.ext.dirs系统变量加载指定的路径中的类库

(3)应用类加载器:负责加载用户路径中的类库。

除了这三种类加载器,还可以通过继承java.lang.ClassLoader实现自定义的类加载器。

双亲委派机制

JVM通过双亲委派机制进行类加载操作。

双亲委派机制是指一个类在收到类加载的请求的时候不会尝试自己加载这个类,而是把这个类加载的请求向上委派给自己的父类去加载,父类在收到该类的加载请求的时候会将其委派给自己的父类,通过这样的方式,所有的类加载请求都被向上委派到启动类加载器中,若父类加载器在收到请求之后发现自己并不能加载这个类,也就是说在对应的路径中没有找到这个类文件,则父类会将类的信息反馈给子类并且委派子类加载器进行加载,直到这个类被加载成功,如果没有找到这个类则会抛出ClassNotFoud的异常。

Java面试篇基础部分-Java的类加载机制

具体流程如下

  • 1、将自定义的类加载器挂载到应用程序类加载器上
  • 2、应用程序类加载器将类加载的请求委托给扩展类加载器。
  • 3、扩展类加载器将类加载请求委托给启动类加载器。
  • 4、启动类加载器在类路径下查找Class文件,发现未找到,则将类加载请求交给扩展类加载器。
  • 5、扩展类加载器在类路径下查找Class文件,如果未发现,则将类加载请求交给应用程序类加载器。
  • 6、应用程序类加载器在加载路径下查找Class文件,如果没有找到则交给自定义类加载器进行处理。
  • 7、如果自定义类加载器在对应的类路径下查找也没有找到对应的Class文件,则会抛出ClassNotFoud异常。
Java面试篇基础部分-Java的类加载机制

双亲委派机制的核心是保障类的唯一性和安全性。例如加载rt.jar包中的Object类的时候,无论是那个类加载器,加载到这个类,最终都需要委派到启动类加载器,这样就保证了类加载的唯一性,如果在JVM中包含有两个相同名称的类,则该类就无法进行正确加载,也就出现了ClassNotDefinition的异常。

OSGI

OSGI(Open Service Gateway Initiative)是Java动态化模块化系统的一系列规范。为了实现Java程序的模块化变成提供基础条件。基于OSGI的程序可以实现模块级的热插拔功能。在程序升级更新的时候,可以只针对需要更新的程序进行停用和重新安装,提高了系统升级的安全性和便捷性。

OSGi和JPMS的交互机制

OSGI提供了面向服务的架构,这个架构为组件提供了动态发现的机制,无论是加入组件还是卸载组件都会被系统中的其他组件所感知到。这样方便了各个组件之间的协调工作。

OSGI定义了模块haul开发的规范,还定义了实现这些规范的依赖服务以及架构操作,现在市面上有很多成熟的应用和实现。但是只有少数的一部分实现了OSGI的方式,因为这种机制的实现就不再遵守JVM的类加载机制以及双亲委派机制和其他的JVM规范。在安全性上不太友好。

文章来源:智云一二三科技

文章标题:Java面试篇基础部分-Java的类加载机制

文章地址:https://www.zhihuclub.com/175089.shtml

关于作者: 智云科技

热门文章

网站地图