首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ClassLoader和双亲委派

ClassLoader和双亲委派

作者头像
PhoenixZheng
发布2018-09-29 11:38:32
7540
发布2018-09-29 11:38:32
举报

上篇文章我们说,A通过自定义ClassLoader去加载B类,从而能够使用到不在同一个目录下的B。

多说两句关于ClassLoader的面试题 我们留了个问题,今天来解释一下。

问题2:A通过ClassLoader加载了B,B对C有引用,那么B和C的ClassLoader是谁?

ClassLoader的层级结构

熟悉Java的朋友应该知道,对于A类来说,如果是默认情况下,它的ClassLoader应该是AppClassLoader, 我们可以通过 A.class.getClassLoader()来获取,输出

sun.misc.Launcher.AppClassLoader@6d06d69c

这是很基础的一个知识点。如果再问深一层,AppClassLoader上面是谁呢? 这里可以用 ClassLoader的 getParent()方法来获取,依次输出父loader的话,结果是

sun.misc.Launcher.AppClassLoader@6d06d69c sun.misc.Launcher.ExtClassLoader@70dea4e parent : null

提到ClassLoader的层级结构的目的是要来解释B的ClassLoader是谁。 上面说到,B类是通过自定义ClassLoader去加载的,那么B跟A的ClassLoader虽然不同,但是它们依然有层级结构, 一样用getClassLoader()方法输出

B clasLoader : DiskClassLoader@33909752 sun.misc.Launcher.AppClassLoader@6d06d69c sun.misc.Launcher.ExtClassLoader@70dea4e

可以看到这时候它的层级结构是这样的。细心的话可以留意一下B的 DiskClassLoader的父loader,跟A的loader的ID。 至于 C 的ClassLoader,其实没有那么复杂,因为ClassLoader在加载B的时候,会发现它对C有引用, 所以同时会把C也加载进来,C的ClassLoader结构也跟B一样

C clasLoader : DiskClassLoader@33909752 sun.misc.Launcher.AppClassLoader@6d06d69c sun.misc.Launcher.ExtClassLoader@70dea4e

另一个有意思的问题

还记得双亲委派吗,Java在寻找类的时候会从根ClassLoader去加载的逻辑? 好了,先记住双亲委派,然后来思考下面这种场景。

我们可以直接在B类里 new 一个 A类对象吗?可以的话,为什么可以?

其实这是一个考察Java基础知识的问题,可以用下面的方法来验证它。 我们写一个B的代码像下面这样

public class B {

  public  void invokeBmethod(){
    System.out.println("B method invoke");
    ClassLoader bLoader = B.class.getClassLoader();
    System.out.println("B clasLoader : " + bLoader);
    while(bLoader != null) {
      System.out.println(bLoader);
      bLoader = bLoader.getParent();
    }
    invokeCmethod();

    A classA = new A(); //<--实例化A
  }

  private  void invokeCmethod() {
    System.out.println("invokeCmethod called");
    C cClass = new C();
    cClass.cMethodInvoke();
  }
}

然后把 A.class 文件放到B的目录中,让它编译成功先。

编译完成后把 A.class 挪出 B 的目录。我们在A的构造函数里输出一段log,看实例化有没有成功,

public class A {

  public A() {
    System.out.println("A constructed");
  }
  //省略一堆main方法
}

运行A,输出结果

java A clas A initiated sun.misc.Launcher.AppClassLoader@6d06d69c sun.misc.Launcher.ExtClassLoader@70dea4e parent : null B method invoke B clasLoader : DiskClassLoader@33909752 sun.misc.Launcher.AppClassLoader@6d06d69c sun.misc.Launcher.ExtClassLoader@70dea4e A constructed //<---- A构造输出

看注释这里,我们虽然没用ClassLoader去加载另外一个目录下的A,但是也能成功的实例化它! 为什么呢,这就是双亲委派。 B在构造A的时候,它会先从根ClassLoader里去找,从上往下,直到在 AppClassLoader 中找到。因此即使不在同一个目录下,也能正常的去用它。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-08-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Android每日一讲 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ClassLoader的层级结构
  • 另一个有意思的问题
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档