如果缺少未使用的类,JVM会抛出异常吗? [英] Does the JVM throw if an unused class is absent?

查看:75
本文介绍了如果缺少未使用的类,JVM会抛出异常吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑程序:

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
    }
}

如果不带参数启动程序,则在运行时类路径中是否需要Foo?

Is Foo required in the runtime classpath if the program is launched without arguments?

研究

当报告链接错误时,Java语言规范相当模糊:

The Java Language Specification is rather vague when Linkage Errors are reported:

该规范为实现链接活动(以及由于递归,加载)发生的时间提供了实现上的灵活性,前提是尊重Java编程语言的语义,并且在其之前对类或接口进行了完整的验证和准备.初始化,并且在链接期间检测到的错误被抛出到程序中某个位置,在该位置,程序采取了一些可能需要链接到错误所涉及的类或接口的操作.

This specification allows an implementation flexibility as to when linking activities (and, because of recursion, loading) take place, provided that the semantics of the Java programming language are respected, that a class or interface is completely verified and prepared before it is initialized, and that errors detected during linkage are thrown at a point in the program where some action is taken by the program that might require linkage to the class or interface involved in the error.

我的测试表明,仅当我实际使用Foo时才会抛出LinkageErrors:

My Tests indicate that LinkageErrors are only thrown when I actually use 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

可以依靠这种行为吗?还是有主流的JVM链接未使用的代码?如果是这样,我如何隔离未使用的代码,以便仅在需要时才进行链接?

Can this behaviour be relied upon? Or is there any mainstream JVM that links unused code? If so, how can I isolate unused code such that it is only linked if needed?

推荐答案

您只需对测试代码进行少量更改即可回答该问题.

You need only small changes to your test code to answer that question.

将类型层次结构更改为

class Bar {}
class Foo extends Bar {}

和程序

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
    }
}

现在,如果不存在Foo,即使在进入main方法(使用HotSpot)之前,该程序也会因错误而失败.原因是验证者需要Foo的定义来检查将其传递给期望Bar的方法是否有效.

Now, the program will fail with an error, if Foo is absent, even before entering the main method (with HotSpot). The reason is that the verifier needs the definition of Foo to check whether passing it to a method expecting Bar is valid.

HotSpot采用快捷方式,不加载类型.这就是为什么Foo不在时您的原始代码不会提早抛出的原因.

HotSpot takes a short-cut, not loading the type, if the types are an exact match or if the target type is java.lang.Object, where the assignment is always valid. That's why your original code does not throw early when Foo is absent.

最重要的是,抛出错误的确切时间点取决于实现,例如可能取决于实际的验证程序实现.正如您已经提到的,所保证的全部是,尝试执行需要链接的动作将引发先前检测到的链接错误.但是您的程序很可能从未尝试过.

The bottom line is that the exact point of time when an error is thrown is implementation dependent, e.g. might depend on the actual verifier implementation. All that is guaranteed is, as you already cited, that an attempt to perform an action that requires linkage will throw previously detected linkage errors. But it is perfectly possible that your program never gets so far to make an attempt.

这篇关于如果缺少未使用的类,JVM会抛出异常吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆