【问题标题】:Why the Java ClassLoader is loading this class为什么 Java ClassLoader 正在加载这个类
【发布时间】:2016-09-16 05:39:52
【问题描述】:

我试图理解为什么 JVM 决定在某些类似乎不需要时加载它。考虑以下示例代码:

public class Foo {
    public void foo() {
    }

    static class Bar {
    }

    public Bar bar() {
        return new Bar();
    }
}

调用new Foo().foo() 时,类加载器不会加载Bar,因为它不需要。但是,如果我们将示例更改为让 bar 返回子类的实例:

public class Foo {    
    public void foo() {
    }

    static class Bar {
    }

    static class BigBar extends Bar {
    }

    public Bar bar() {
        return new BigBar();
    }
}

调用new Foo().foo() 会导致类加载器同时加载BarBigBar 类,即使它们都不需要。为什么?

除了这个特定的场景之外,有没有办法了解 JVM 为何决定它需要加载一个类?

【问题讨论】:

  • 你的问题很神秘。如果你有JDK8,将使用JDK8。不能同时使用 2 个 JDK。
  • 您是否使用-target 1.7 编译了代码并测试了它如何在7 版本的JRE 上运行?这将是一种更直接的方式来查看它是如何处理的,而不是通过猜测类加载器在做什么。
  • @JoshStone 哪个代码?哪些课? “一些代码试图从 Java 8 加载一些类”并没有提供太多的工作。
  • 我有一个类,其中包含一些返回 CompletableFuture(JDK 8 类)的方法。根据我对 Java 类加载的理解,在我实际调用返回它的方法之前,不应加载 CompletableFuture。我没有调用这样的方法,但它仍在加载中。
  • @JoshStone 我很惊讶CompletableFuture 不会在那个时候被加载,但至少在这种情况下很容易解释当你在那里有null 时,类型变得无关紧要。它不是“(CompletableFuture)null”,它只是一个简单的 null,并且任何东西都不需要类信息。

标签: java classloader


【解决方案1】:

这是来自Internals of Java Class Loading的好读物

每当通过键入 java MyMainClass 启动新的 JVM 时, “bootstrap class loader”负责加载关键的Java类 像 java.lang.Object 和其他运行时代码一样先进入内存。这 运行时类打包在 JRE\lib\rt.jar 文件中。我们 在 Java 中找不到引导类加载器的详细信息 文档,因为这是本机实现。对于相同的 原因,引导类加载器的行为也会有所不同 跨 JVM。

在相关说明中,如果我们尝试获取类加载器,我们将得到 null 一个核心 Java 运行时类,如下所示:

log(java.lang.String.class.getClassLoader());

接下来是 Java 扩展类加载器。我们可以存储扩展 库,提供超出核心 Java 的功能的库 运行时代码,在 java.ext.dirs 属性给出的路径中。这 ExtClassLoader 负责加载保存在 java.ext.dirs 路径。开发人员可以添加他或她自己的应用程序 .jar 文件或他或她可能需要添加到 此扩展目录的类路径,以便它们将由 扩展类加载器。

来自开发者的第三个也是最重要的类加载器 透视图是 AppClassLoader。应用程序类加载器是 负责加载保存在路径中的所有类 对应java.class.path系统属性。

【讨论】:

  • 我对类加载很熟悉。我需要了解的是在这个确切的场景中触发类加载的原因,因为它并不明显。
【解决方案2】:

很好解释http://javarevisited.blogspot.in/2012/07/when-class-loading-initialization-java-example.html

当 Class 在 Java 中加载时 类加载是由 Java 中的 ClassLoaders 完成的,可以实现为在另一个类引用它时立即加载一个类,或者延迟加载该类,直到需要进行类初始化。如果 Class 在实际使用之前被加载,它可以在初始化之前放在里面。我相信这可能因JVM而异。虽然 JLS 保证在需要静态初始化时加载一个类。 当一个类在 Java 中初始化时 1) 使用 new() 关键字或使用反射使用 class.forName() 创建类的实例,这可能会在 Java 中抛出 ClassNotFoundException。

2) 调用 Class 的静态方法。 3) 分配一个静态字段Class。 4) 使用了一个类的静态字段,它不是一个常量变量。 5) 如果 Class 是顶级类并且执行词法嵌套在类中的断言语句。

【讨论】:

  • 你读过这个问题吗?类在被引用或使用之前被加载。根据您发布的链接,不应加载该类。
猜你喜欢
  • 1970-01-01
  • 2014-08-23
  • 2015-08-22
  • 2015-07-12
  • 2018-07-05
  • 1970-01-01
  • 1970-01-01
  • 2016-09-27
  • 2020-03-10
相关资源
最近更新 更多