跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 关于 ClassLoader 的一些疑问
未分類
9 5 月 2020

关于 ClassLoader 的一些疑问

关于 ClassLoader 的一些疑问

資深大佬 : yangyuhan12138 17

众所周知

jvm 里 class 的唯一标识是 classloader+包+类
现在我自定义了一个 classloader

public class MyClassLoader extends ClassLoader 

从外部加载指定类进入 jvm

        MyClassLoader mcl = new MyClassLoader();         Class<?> clazz = Class.forName("com.yuhan.demo.controller.People", true, mcl);         obj = clazz.newInstance();         System.out.println(obj.getClass().getClassLoader());//打印出我们的自定义类加载器  

这种加载方法应该是使用了双亲委托机制如果 AppClassLoader 已经加载过 People 了则不会重新加载
控制台输出

[email protected] 

如果我们将 People.class 从 classpath 中删除放到其他地方,避免 AppClassLoader 直接加载
则输出

[email protected] 

但是如果我们直接这样调用

       mcl = new MyClassLoader();        aClass = mcl.findClass("com.yuhan.demo.controller.People");        obj =aClass.newInstance();        System.out.println(obj.getClass().getClassLoader());//打印出我们的自定义类加载器 

则不管 AppClassLoader 是否加载过都会由 MyClassLoader 来加载(相当于绕过了双亲?)

现在我有个疑问就是我用 findClass 方法加载了一个 jvm 中已经存在的 class(包名类名都相同),相当于 jvm 中就有两个相同的 class 了(jvm 中是允许这样存在的因为 classloader 不同) 但是 java 中使用类的时候只指定了包名和类名并没有指定 classloader 那么 java 是如何保证我 new People 的时候是是用的 AppClassLoader 的 People 而不是 MyClassLoader 的 People 呢

我的猜测是我们直接使用类的时候 java 加上了默认的 classloader 从而过滤调了我们自己加载的类,而我们自己加载的类则只能通过反射来调用

大佬有話說 (12)

  • 資深大佬 : kaedea

    线程 ClassLoader 了解一下

  • 主 資深大佬 : yangyuhan12138

    @kaedea
    谢谢大佬的回复,我去看了下 context class loader 并做了如下实验
    “`
    MyClassLoader loader = new MyClassLoader();
    Thread.currentThread().setContextClassLoader(loader);
    obj = new People();
    System.out.println(obj.getClass());
    System.out.println(obj.getClass().getClassLoader());//打印出我们的自定义类加载器
    “`
    输出
    class com.yuhan.demo.controller.People
    [email protected]

    开始我以为的是设置了 context class loader 之后,会去取我设置的 classloader load 的 class 来进行实例化,但是好像并不是这样,运行结果依然为 AppClassLoader,如果我想要取 MyClassLoader load 的 People 还是得 Thread.currentThread().getContextClassLoader() 将 MyClassLoader 取出来之后再 loadclass,所以这个地方其实相当于只是多个个线程副本变量而已,如果直接 new People()的 People 还是 AppClassLoader load 的 People
    所以我的问题的答案应该就是我如果不主动指定 classloader 来 loadclass 的话 我们是使的所有类都是由 Java 中的类加载器来加载的?

  • 資深大佬 : james122333

    果然很可疑阿 haha 有讲与没讲差不多果然才是对的

  • 資深大佬 : sioncheng

    双亲委派模型,Bootstrap ClassLoader /ExtClassLoader/ AppClassLoader https://blog.csdn.net/briblue/article/details/54973413
    Thread Context Class Loader 与 SPI https://blog.csdn.net/liuchangqing123/article/details/52304644

  • 主 資深大佬 : yangyuhan12138

    @james122333 啊?
    @sioncheng 这些我都看了呀…疑问还是没解决

  • 資深大佬 : mazai

    你要找的答案就在 Launcher 这个类里面,首先 JVM 在初始化的时候启动类加载器会首先被虚拟机执行(一段 C++代码),而 Launcher 这个类正是启动类加载器来加载的。

    他有一个全局静态变量 private static Launcher launcher = new Launcher(); 因此 Launcher 的构造函数会被调用,以下我截出几段构造函数的代码你就明白了:
    this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);

    Thread.currentThread().setContextClassLoader(this.loader);

    var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();

    更详细的你自己去看 Launcher 这个类的代码就好了。

  • 資深大佬 : fantastM

    你想问是的 ClassLoader A 加载了 Class A,为什么在没有显式声明使用 ClassLoader A 的情况下就可以加载 Class A 依赖的 Class B 吗

  • 主 資深大佬 : yangyuhan12138

    @fantastM 不是呀….我的意思是同名 class 不同 classloader 加载进 jvm 的 在我们直接 new 的时候到底是使用的那个 classloader 加载进来的 class

  • 資深大佬 : pursuer

    1 、java 不需要保证类是从哪个 classloader 加载的
    2 、并不是只能通过反射调用,你甚至可以自定义 classloader 破坏双亲委派替换掉一个本来已经加载的类去

  • 資深大佬 : fantastM

    「我们直接 new 的时候」这时候程序已经运行在一个被 ClassLoader 加载的类里了,默认就会用这个 ClassLoader 去加载当前类依赖的还没有被加载的其它类。

  • 主 資深大佬 : yangyuhan12138

    @fantastM 已加载的也会优先使用当前 classloader 加载的 我刚试的就是这样

  • 主 資深大佬 : yangyuhan12138

    @pursuer 我现在不就是这样做的吗 加载一个已经存在的类 只是 classloader 不同

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具