可能缺少运行时依赖项的 Java 类

tuc*_*uxi 6 java classloader dependency-management

我有一个依赖于库 X 的实用程序类 U,并且必须放入一个包中,该包将在具有 X 可用的程序(它应该执行其正常操作)和没有 X 的地方(它不应该执行任何操作)中使用。在不将类分成两部分的情况下,我找到了一个简单的模式来解决这个问题:

package foo;
import bar.MisteriousX;

public class U {
    static private boolean isXPresent = false;
    static {
        try {
            isXPresent = (null != U.class.getClassLoader().loadClass("bar.MisteriousX"));
        } catch (Exception e) {
            // loading of a sample X class failed: no X for you
        }
    }
    public static void doSomething() {
        if (isXPresent) {
            new Runnable() {
                public void run() { 
                    System.err.println("X says " + MisteriousX.say());
                }
            }.run();
        } else {
            System.err.println("X is not there");
        }
    }
    public static void main(String args[]) { doSomething(); } 
}
Run Code Online (Sandbox Code Playgroud)

使用此模式,U 需要存在 X 才能编译,但在存在或不存在 X 的情况下运行时都会按预期工作。除非对 X 库的所有访问都在内部类内部,否则此代码将引发类加载器异常。

问题:导入解析是否保证在任何地方都能像这样工作,或者它取决于 JVM/ClassLoader 实现吗?这有既定的模式吗?上面的代码片段是否太老套而无法投入生产?

MvG*_*MvG 4

一般来说,当一个类第一次加载时,如果它引用了一个不存在的类,则可能会导致错误。所以是的,让一个类进行检查,而另一个类在没有反射的情况下实际访问外部包将按预期工作,至少在我迄今为止看到的所有实现上是这样。它不一定是内部类。

\n\n

JVM 规范中的链接部分为实现提供了很大的自由度如果您不使用两类方法,那么使用急切链接的实现中的验证将导致尝试加载,从而导致. 规范不要求对引用类进行验证,但也不禁止这种早期验证。但它确实要求U XLinkageError

\n\n
\n

解析期间检测到的任何错误都必须在程序中(直接或间接)使用对类或接口的符号引用的点处抛出。

\n
\n\n

似乎您应该可以安全地假设仅当您实际访问内部类时才会引发错误。如果你看看这个答案的历史,你会发现我已经两次改变了我的观点,所以不能保证我这次读得正确\xe2\x80\xa6 :-/

\n