是否保证(默认的系统)Java类加载器不尝试加载正在运行的代码中未引用的类?我的意思的几个例子:
framework.jar
我知道其中包含对其他library.jar
类的引用,但我只使用不包含这些引用的框架的这一部分。离开library.jar
是否安全?快速测试它看起来像上面假设的那样工作,无论如何加载未使用的类没有多大意义,但是否有保证?
添加:似乎我的“静态块在首次加载类时运行”上面的语句有点不正确。在没有运行它们的情况下,加载类(一件事)绝对是可能的(另一件事)。所以我对这两种情况都感兴趣;保证类没有加载,而不是运行。
答案 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将是 在此之前立即初始化 第一次出现任何一个 以下内容:
只有在第一次使用类时才会执行静态块。
答案 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中有一个类,它将被加载”某种类型的。