Java 双亲委派机制 的介绍及演示 以及Scala的机制

Java的三个类加载器

  • Bootstrap classLoader (启动类加载器)
  • ExtClassLoader (扩展类加载器)
  • AppClassLoader (应用类加载器)

三者为上下级关系,如图:

 产生机制的原因

我们在写类的时候,由于类名限制不多,可能会出现我们写的类和java自带的类重名的情况。

极端举例,我们写了一个java.lang.String类,与java自带的冲突了。此时,我们就需要一套处理这个问题的机制,即为

-- 双亲委派机制  。

首先,当我们加载一个类的时候,JVM并不会马上加载并起作用,而是会先判断java中是否已存在该名的类。如果有重名的情况下,出于安全考量,是绝对不会使用我们自己定义的类。比如我们自己定义了一个java.lang.String类,而我们代码中大量使用了java自带的java.lang.String类中的方法,此时如果加载我们自定义的类,那么代码就无法运行了。

 

三种加载器的加载位置

  • Bootstrap classLoader (启动类加载器):负责加载 jdk 核心类如 rt.jar(包含java.lang)
  • ExtClassLoader (扩展类加载器):主要负责加载 jre/lib/ext 目录下的一些扩展的jar。
  • AppClassLoader (应用类加载器):主要负责加载环境变量classpath下的类

 

委派机制

  1. 当我们的应用类加载器加载类的时候,先检查自己是否加载过,如果有那就无需再加载了。如果没有加载过,也不会马上加载,而会委托我们的上一级 -扩展类加载器 加载 (通过调用父加载器的loadClass方法)。
  2. 扩展类加载器先检查自己是否加载过,如果有那就无需再加载了。如果没有加载过,也不会马上加载,而是会委托上一级 -启动类加载器 加载。
  3. 启动类加载器如果发现这个类在他的加载位置已经存在,就会将这个类加载到内存中。如果找不到此类,就会往下走,走到扩展类加载器
  4. 扩展类加载器如果发现这个类在他的加载位置已经存在,就会将这个类加载到内存中。如果找不到此类,就会往下走,走到应用类加载器
  5. 应用类加载器如果发现这个类在他的加载位置已经存在,就会将这个类加载到内存中。如果找不到此类,会抛出异常:ClassNotFoundException

 

演示机制

在 java8 目录,jre 目录下新建文件夹 classes:

 将自己编译过的Test.class文件放入classes文件夹

(lib中放的都是jar包,单独的 class文件放入我们自己创建的 classes文件夹中)

代码内容如下:

public class Test {
    public static void main(String[] args) {
        System.out.println("aaaa");
    }
}

以上是为了让启动类加载器可以找到该类。

接着再将编译过 Test.class 放在 扩展类加载器 可以加载到的位置:

修改后的代码内容:

public class Test {
    public static void main(String[] args) {
        System.out.println("bbbb");
    }
}

 

最后修改代码为如下,并编译:

public class Test {
    public static void main(String[] args) {
        System.out.println("cccc");
    }
}

接着,在任意位置,执行我们的Test.class文件, 结果如下

结果与机制描述相符合。

将 jre/classes 的 Test.class 删除, 执行输出 "bbbb"

再将 jre/lib/ext 下的 Test.class 删除, 执行输出 "cccc"

 

Scala中没有双亲委派机制

object Test {
  def main(args: Array[String]): Unit = {
    val hashMap = new java.util.HashMap   //调用的子包中的HashMap类
}

package java{
  package util {
    class HashMap {
      println("I am not java.util.HashMap...")
    }
  }
}

执行如上代码:

 

由此可见,双亲委派机制在Scala中并 不起作用

那么,我们应该如何调用原本 java.util.HashMap 呢? 

很简单,只需要在前面加上 "_root_"   :

//这样可以访问到java.util中的类
    val hashmap = new _root_.java.util.HashMap

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值