Java类加载器是否保证不加载未使用的类?

时间:2010-08-15 14:58:22

标签: java classloader

是否保证(默认的系统)Java类加载器尝试加载正在运行的代码中未引用的类?我的意思的几个例子:

  • 我使用的framework.jar我知道其中包含对其他library.jar类的引用,但我只使用不包含这些引用的框架的这一部分。离开library.jar是否安全?
  • 首次加载类时会运行静态块。如果没有正在运行的代码包含对特定类的引用,是否确定它的静态块未运行?

快速测试它看起来像上面假设的那样工作,无论如何加载未使用的类没有多大意义,但是否有保证

添加:似乎我的“静态块在首次加载类时运行”上面的语句有点不正确。在没有运行它们的情况下,加载类(一件事)绝对是可能的(另一件事)。所以我对这两种情况都感兴趣;保证类没有加载,而不是运行

7 个答案:

答案 0 :(得分:8)

没有这样的保证 1 wrt加载类。

但是,您可以保证静态块不会过早运行。触发类初始化的事件在JLS 12.4.1中指定。

  

类或接口类型T将在第一次出现以下任何一个之前立即初始化:

     
      
  • T是一个类,创建了一个T实例。
  •   
  • T是一个类,调用T声明的静态方法。
  •   
  • 分配由T声明的静态字段。
  •   
  • 使用由T声明的静态字段,该字段不是常量变量(§4.12.4)。
  •   
  • T是顶级类,并且执行词法嵌套在T中的断言语句(第14.10节)。
  •   

1 - 据观察,当前生成的Java实现不会不必要地加载类,但这不是保证。唯一的保证是它在官方规范中所写的内容。

答案 1 :(得分:4)

java specification个州

  

加载过程由。实现   ClassLoader类及其类   子类。不同的子类   ClassLoader可以实现不同的   加载政策。   特别是,类加载器可以   缓存二进制表示   类和接口,预取它们   根据预期用途或加载a   一组相关的课程。

因此类加载器可以自由预取类文件。

  

类或接口类型T将是   在此之前立即初始化   第一次出现任何一个   以下内容:

  • T是一个类,创建了一个T实例。
  • T是一个类,调用T声明的静态方法。
  • 分配由T声明的静态字段。
  • 使用由T声明的静态字段,对字段的引用不是编译时常量(第15.28节)。编译时常量的引用必须在编译时解析为编译时常量值的副本,因此使用这样的字段永远不会导致初始化。

只有在第一次使用类时才会执行静态块。

答案 2 :(得分:1)

我认为没有这样的保证。首先,我见过代码扫描程序,它可以在应用程序启动期间处理来自整个包层次结构/ JAR的注释;他们马上违反了这个假设。

为什么这很重要?你通常是在高度可控的系统负载之后,所以任何重要的事情都会在你无论如何强迫它的地方......

答案 3 :(得分:1)

引入类的东西是从Java字节代码引用它们(这可能会引入其他类)。如果您运行的类没有对类X的任何引用,则不会加载它。

但请注意,有更新的方法可以注册,例如通过META-INF提供的服务。这些类也需要加载。

您可以随时使用“-verbose”运行以在加载时查看类 - 顺序清楚地表明它们在需要时加载。

答案 4 :(得分:1)

如果您不使用反射,则可以使用死代码删除工具(例如ProGuard)静态检查使用哪些类。它将分析您的代码并确定所使用的所有类。在此基础上,它删除了未使用的代码,包括库中未使用的代码。

如果您的代码或库使用反射来加载类,那么您将需要对应用程序运行全面覆盖测试并记录所有加载的类,这些类指示ProGuard保留。

答案 5 :(得分:0)

其他海报没有提到这样的保证。但是你的问题和你的担忧并没有相互关联。为了让你离开library.jar,你不需要这样的保证。

有许多框架可以在运行时发现其他框架的存在与否。例如:Commons-logging发现了许多其他框架。 Spring Web流程在运行时发现了脚本框架(例如OGNL)。这些框架显然是使用所有依赖框架编译的,但它们不必在运行时存在。

因此,在运行时将library.jar保留在外是完全可以接受的。

答案 6 :(得分:0)

是。

考虑以下事项。如果将以下代码添加到library.jar类:

 public ShutDown {static { System.exit(-1); }}

默认系统不会自动加载该代码,因为现有代码都没有引用或者知道ShutDown类,也没有办法加载它,Java类加载器也没有不要试图从jar中加载随机类。

在前面的答案中描述了加载类的方法,如果仔细查看它们,它们中没有一个包含“如果jar中有一个类,它将被加载”某种类型的