mer*_*ike 9 java jvm linker-errors
考虑该计划:
public class Test {
public static void main(String[] args) {
if (Arrays.asList(args).contains("--withFoo")) {
use(new Foo());
}
}
static void use(Foo foo) {
// do something with foo
}
}
Run Code Online (Sandbox Code Playgroud)
如果在没有参数的情况下启动程序,那么运行时类路径中是否需要Foo?
研究
报告链接错误时,Java语言规范相当模糊:
该规范允许实现灵活性,以便何时发生链接活动(以及由于递归,加载),只要遵循Java编程语言的语义,在初始化之前完全验证和准备类或接口,并且在链接期间检测到的错误被抛出到程序中的某个点,在该点上程序可能需要链接到错误中涉及的类或接口.
我的测试表明只有在我实际使用时才会抛出LinkageErrors Foo:
$ rm Foo.class
$ java Test
$ java Test --withFoo
Exception in thread "main" java.lang.NoClassDefFoundError: Foo
at Test.main(Test.java:11)
Caused by: java.lang.ClassNotFoundException: Foo
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 1 more
Run Code Online (Sandbox Code Playgroud)
可以依赖这种行为吗?或者是否有任何主流JVM链接未使用的代码?如果是这样,我如何隔离未使用的代码,以便仅在需要时才链接?
您只需对测试代码进行少量更改即可回答该问题.
将类型层次更改为
class Bar {}
class Foo extends Bar {}
Run Code Online (Sandbox Code Playgroud)
和程序
public class Test {
public static void main(String[] args) {
if (Arrays.asList(args).contains("--withFoo")) {
use(new Foo());
}
}
static void use(Bar foo) {
// don't need actual code
}
}
Run Code Online (Sandbox Code Playgroud)
现在,Foo即使在输入main方法之前(使用HotSpot),程序也将失败并显示错误(如果不存在).原因是验证者需要定义Foo以检查是否将其传递给期望的方法Bar是有效的.
如果类型是完全匹配或者目标类型是java.lang.Object,则HotSpot采用快捷方式,而不是加载类型,其中赋值始终有效.这就是为什么你的原始代码在Foo缺席时不会提前抛出的原因.
底线是抛出错误的确切时间点取决于实现,例如可能取决于实际的验证器实现.正如您已经引用的那样,所有保证的是,尝试执行需要链接的操作将抛出先前检测到的链接错误.但是你的程序完全有可能永远不会到目前为止尝试.
| 归档时间: |
|
| 查看次数: |
304 次 |
| 最近记录: |