【问题标题】:Java is there a way to load a class that has been already loaded by the System ClassLoader by a different one?Java有没有办法加载一个已经被系统类加载器加载的类?
【发布时间】:2023-03-12 04:59:01
【问题描述】:

(可怕的标题,我知道)

解释这一点的最好方法是,我需要加载一些将在运行时从 URLClassLoader 加载的类,因为这些类引用了系统类加载器已经加载的类的实例,它们不能由于其他一些问题而重新加载。

另外,我愿意更改我的代码,以便我可以使用 System ClassLoader 从类路径中的 jar 加载类,但我无法做到这一点。

【问题讨论】:

    标签: java system classloader urlclassloader


    【解决方案1】:

    没有。每个类加载器都将引导类加载器作为祖先,尝试加载已经在类加载器中定义的类只会导致使用祖先的版本。这是为了防止 java.lang.Object 和其他内部函数被重新定义。

    来自javadoc for ClassLoader

    ClassLoader 类使用委托模型来搜索类和资源。 ClassLoader 的每个实例都有一个关联的父类加载器。 当请求查找类或资源时,ClassLoader 实例将在尝试查找类或资源本身之前将对该类或资源的搜索委托给其父类加载器。 虚拟机的内置在类加载器中,称为“引导类加载器”,它本身没有父级,但可以作为ClassLoader 实例的父级。

    您可以定义一个自定义类加载器来公开defineClass 而不会被findClass 调用并避免在findClass 中发生的委托,但我不会依赖defineClass(className, bytes) 按预期工作parent.findClass(className) 存在时的 JVM。

    【讨论】:

    • 没有什么可以强制任何特定的 ClassLoader 实现/子类实际实现此行为。
    • @bmargulies,我的印象是resolveClass 是最终的,它实现了委托,它是所有已加载、初始化的Class 实例的生产的看门人。
    • @bmargulies,我再次查看了第 12.3 节,但没有看到任何替代联动机制。假设我在自定义ClassLoader 中成功定义了java.lang.Object,然后我想加载另一个类,其字节码包含对java.lang.Object 的符号引用。有什么替代链接机制会导致第二个类中的java.lang.Object 解析为与父类加载器版本不同的java.lang.Object
    • @bmargulies,我对我写的答案没有信心,因为我从未在生产 JVM 上工作过,你对“可能”有很好的看法,但我找不到任何明确的规范或文档中以一种或另一种方式衡量的语言。
    【解决方案2】:

    是的,您可以定义另一个类加载器并加载该类。

    根据规格

    “在运行时,一个类或接口不仅仅由它的名称决定,而是由一对:它的完全限定名称和它的定义类加载器决定。每个这样的类或接口都属于一个单独的运行时包。类或接口的运行时包由包名和定义类或接口的类加载器决定。"

    【讨论】:

      【解决方案3】:

      是的。但是你需要稍微小心,因为默认的父类加载器是系统类加载器,而不是引导类加载器。我建议使用java.net.URLClassLoader.newInstance(myURLs, null)。如果你想成为flash,从系统类加载器中获取父类加载器,这将包括扩展类。

      (注意,术语有点扭曲,因为它可以追溯到 Java2 之前,当时类路径包含现在的 bootclasspath(安装程序很痛苦)。所以系统类不由系统类加载器加载。)

      【讨论】:

        猜你喜欢
        • 2010-12-21
        • 2012-07-08
        • 2017-09-05
        • 1970-01-01
        • 1970-01-01
        • 2015-01-04
        • 1970-01-01
        • 1970-01-01
        • 2010-11-16
        相关资源
        最近更新 更多