扫码关注公众号

JVM考点之类加载过程
12-05
29观看
01

java中类加载的过程是什么?

加载该阶段虚拟机需要完成三件事:①通过一个类的全限定类名获取定义类的二进制字节流。②将字节流所代表的静态存储结构转化为方法区的运行时数据区。

来自:jvm虚拟机相关-类的加载过程
02

jvm有哪些类加载器?

自JDK1.2起Java一直保持三层类加载器:启动类加载器在JVM启动时创建,负责加载最核心的类,例如Object、System等。无法被程

来自:jvm虚拟机相关-类的加载过程
03

如何使一个类不可变?

1.将类声明为final,使其无法被继承。2.所有域都用private修饰,不允许直接访问。3.不提供变量的setter方法。4.所有可变域

来自:jvm虚拟机相关-类的加载过程
04

类加载的方式(百度面试题)

类加载分为动态加载和静态加载。动态加载是从外存储器中加载类,一般类加载机制分析的也是动态加载。静态加载本质上是从内存中创建类的实例对象,此时类已经被加载到内存中。一.静态加载1.通过new关键字来创建Test的实例对象。二.动态加载1.通过Class.forName()来加载类,然后调用类的newInstance()方法实例化对象。2.通过类加载器的loadClass()方法来加载类,然后调用类的newInstance()方法实例化对象。这里有几个需要比较的地方:1.通过new关键字实例化类的对象和通过Class.forName()加载类是当前类加载器。即this.getClass.getClassLoader,只能在当前类路径或者导入的类路径下寻找类。而用指定的classLoader来加载类可以从当前路径外寻找类,这里的classLoader甚至可以用户自定义。2.我们知道类加载机制的三个过程主要是加载-->连接-->初始化。Class.forName()实际调用的是Class.forName(className,true,this.getClass.getClassLoader),第二个参数表示加载完后是否立即初始化,第三个参数即前文提到的表示是当前类加载器。classLoader.loadClass()实际调用的是classLoader.loadClass(className,false),第二个参数表示加载完成后是否连接,即用此方法加载类,加载完成后不会去初始化,而用Class.forName()加载类加载完成后可以被初始化。所以有些类如果加载完成后需要立即被初始化则必须使用Class.forName()。例如在加载数据库驱动时,一般用Class.forName("com.mysql.jdbc.Driver")。这是因为该驱动有一个在静态代码块中注册驱动的过程,所以需要被初始化。3.有两个异常静态加载类时出现的一般是NoClassDefFoundError。动态加载类时出现的一般是ClassNotFoundException。这两者经常被用来比较,其实区别很大。NoClassDefFoundError是错误,不方便被捕捉也不需要被捕捉,不应该尝试从error中恢复程序。他是由于在使用new关键字实例化类的对象时,在内存中找不到对象了,一般比较少见,在运行时发生,即编译时可以找到类运行时却找不到了。而ClassNotFoundException是异常,是可以被捕捉的,应该捕捉并处理尝试恢复程序。这是由于利用类名动态加载类的时候,在外存储器类路径下找不到该类或者其依赖的jar包,还有一个导致其的原因是在同一个包中同一个类被不同的类加载器加载了两遍。

来自:jvm虚拟机相关-类的加载过程
05

为什么需要双亲委派?

因为类加载器之间有严格的层次关系,那么也就使得Java类也随之具备了层次关系。或者说这种层次关系是优先级。比如一个定义在java.lang包下的类,因为它被存放在rt.jar之中,所以在被加载过程汇总,会被一直委托到BootstrapClassLoader,最终由BootstrapClassLoader所加载。而一个用户自定义的com.hollis.ClassHollis类,他也会被一直委托到BootstrapClassLoader,但是因为BootstrapClassLoader不负责加载该类,那么会在由ExtentionClassLoader尝试加载,而ExtentionClassLoader也不负责这个类的加载,最终才会被ApplicationClassLoader加载。这种机制有几个好处。首先,通过委派的方式,可以避免类的重复加载,当父加载器已经加载过某一个类时,子加载器就不会再重新加载这个类。另外,通过双亲委派的方式,还保证了安全性。因为BootstrapClassLoader在加载的时候,只会加载JAVA_HOME中的jar包里面的类,如java.lang.Integer,那么这个类是不会被随意替换的,除非有人跑到你的机器上,破坏你的JDK。那么,就可以避免有人自定义一个有破坏功能的java.lang.Integer被加载。这样可以有效的防止核心JavaAPI被篡改。

来自:jvm虚拟机相关-类的加载过程
06

如何主动破坏双亲委派机制?

知道了双亲委派模型的实现,那么想要破坏双亲委派机制就很简单了。因为他的双亲委派过程都是在loadClass方法中实现的,那么想要破坏这种机制,那么就自定义一个类加载器,重写其中的loadClass方法,使其不进行双亲委派即可。

来自:jvm虚拟机相关-类的加载过程
专栏
java语言-jvm虚拟机相关-类的加载过程
4专栏
0课程
6 试题