Java虚拟机设计团队有意把类加载阶段中的“通过一个类的全限定名来获取描述该类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需的类。实现这个动作的代码被称为“类加载器”。
类加载器用于实现类的加载动作,对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。
在比较两个类是否“相等”时,如果两个类来源于同一个 Class文件且被同一个Java虚拟机加载,但只要加载它们的类加载器不同,那这两个类就必定不相等。因此,比较两个类是否“相 等”,只有在这两个类是由同一个类加载器加载的前提下才有意义。
从JVM角度来看,只存在两种不同的类加载器:
但从我们开发者的角度来看,可以把类加载器细化如下:
Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象。而且加载某个类的class文件时,Java虚拟机采用的就是双亲委派模型。
双亲委派模型的工作过程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加 载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的 加载请求最终都应该传送到最顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请 求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去完成加载。
双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都应有自己的父类加载器。不过这里类加载器之间的父子关系一般不是以继承的关系来实现的,而是通常使用组合关系来复用父加载器的代码。
双亲委派模型实现位于java.lang.ClassLoader
中的loadClass(java.lang.String, boolean)
方法中,具体如下:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
可以解释如下:先检查请求加载的类型是否已经被加载过,若没有则调用父加载器的 loadClass()方法,若父加载器为空则默认使用启动类加载器作为父加载器。假如父类加载器加载失败, 抛出ClassNotFoundException异常的话,才调用自己的findClass()方法尝试进行加载。
沙箱安全机制就是将java代码限定在虚拟机特定的运行范围中,并且严格限制代码对本地系统资源的访问,通过这样的措施来保证对代码的有效隔离,防止对系统造成破坏。
例如:
我们自定义一个String类,但是在加载自定义String类的时候会率先使用引导类加载器加载,而引导类加载器在加载的过程中会先加载jdk自带的文件(rt.jar包中java\lang \string.class)。这样可以保证对java核心源代码的保护,这就是沙箱安全机制。
在Java的日常应用程序开发中,类的加载几乎是由这三种类加载器互相配合来完成加载的,如果用户认为有必要,还可以加入自定义的类加载器来进行拓展,典型的如增加除了磁盘位置之外的Class文件来源,或者通过类 加载器实现类的隔离、重载等功能。
自定义类加载器可以实现以下功能:
类的主动使用和被动使用区别在于是否会导致类的初始化,导致类的初始化为类的主动适用,不导致类的初始化为类的被动使用。
主动使用有以下7中情况:
除以上7种情况外都是被动使用。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://wang11.blog.csdn.net/article/details/125665843
内容来源于网络,如有侵权,请联系作者删除!