方法体中使用的类根据方法返回类型延迟加载或提前加载

问题描述 投票:0回答:1

我正在制作一个支持多个版本 API 的 API 包装器库。最近的 API 版本中添加了一个公共类。我正在尝试针对最新的 API 版本编译包装器,并在运行时检查新类是否存在。我试图避免反射,而是捕捉

NoClassDefFoundError
并相应地设置一个标志。

它一直有效,直到我添加一个返回不存在的类extends的类的方法。然后我的库无法加载。我的意思是:

BaseClass
存在;
ChildClass
不存在;该方法在内部使用
ChildClass
。如果该方法返回
BaseClass
库加载失败。如果该方法返回
Object
库加载并且错误被延迟并且可以被捕获。

标准的哪一部分描述了这种行为?

这是一个最小的例子:

public class TestLoading {

    public static void main(String[] args) throws Exception {
        Class.forName(BaseClass.class.getName());
        // Class.forName(B.class.getName())
        URL classFileB =
            TestLoading.class.getResource(TestLoading.class.getSimpleName() + "$ChildClass.class");
        if (classFileB != null) {
            if (!"file".equals(classFileB.getProtocol())) {
                throw new UnsupportedOperationException();
            }
            Path path = new File(classFileB.getPath()).toPath();
            System.out.println("deleting: " + path);
            Files.delete(path);
        }

        loadMyClass(ObjectReturner.class.getName());
        loadMyClass(BaseClassReturner.class.getName());
    }

    private static void loadMyClass(String name) throws ClassNotFoundException {
        System.out.println("loading: " + name + "...");
        try {
            Class.forName(name);
        } catch (Throwable e) {
            e.printStackTrace(System.out);
        }
    }

    public static class BaseClass {

        static {
            System.out.println("loaded: " + BaseClass.class.getName());
        }
    }

    public static class ChildClass extends BaseClass {

        static {
            System.out.println("loaded: " + ChildClass.class.getName());
        }
    }

    public static class ObjectReturner {

        static {
            System.out.println("loaded: " + ObjectReturner.class.getName());
        }

        public Object getObject() {
            return new ChildClass();
        }
    }

    public static class BaseClassReturner {

        static {
            System.out.println("loaded: " + BaseClassReturner.class.getName());
        }

        public BaseClass getObject() {
            if ("".length() == 10) {
                return new ChildClass();
            } else {
                return null;
            }
        }
    }
}

程序输出

loaded: snippet.TestLoading$BaseClass
deleting: C:\keep\eclipse\formendix\_pasted_code_\target\classes\snippet\TestLoading$ChildClass.class
loading: snippet.TestLoading$ObjectReturner...
loaded: snippet.TestLoading$ObjectReturner
loading: snippet.TestLoading$BaseClassReturner...
java.lang.NoClassDefFoundError: snippet/TestLoading$ChildClass
    at java.base/java.lang.Class.forName0(Native Method)
    at java.base/java.lang.Class.forName(Class.java:377)
    at snippet.TestLoading.loadMyClass(TestLoading.java:31)
    at snippet.TestLoading.main(TestLoading.java:25)
Caused by: java.lang.ClassNotFoundException: snippet.TestLoading$ChildClass
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:606)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:168)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    ... 4 more
java classloader
1个回答
0
投票

我已经使用

-Xlog:class+init
在 Java 11 上运行您的代码并得到以下输出:

loading: com.olympus.trade.util.TestLoading$ObjectReturner...
[0.434s][info][class,init] Start class verification for: com.olympus.trade.util.TestLoading$ObjectReturner
[0.434s][info][class,init] 737 Initializing 'java/util/AbstractSequentialList'(no method) (0x000000080009a570)
[0.434s][info][class,init] End class verification for: com.olympus.trade.util.TestLoading$ObjectReturner
[0.434s][info][class,init] 738 Initializing 'java/util/LinkedList'(no method) (0x000000080009aa40)
[0.434s][info][class,init] 739 Initializing 'com/olympus/trade/util/TestLoading$ObjectReturner' (0x0000000800067450)
loaded: com.olympus.trade.util.TestLoading$ObjectReturner
[0.434s][info][class,init] 740 Initializing 'java/util/LinkedList$Node'(no method) (0x000000080009b1b0)
[0.435s][info][class,init] 741 Initializing 'sun/util/locale/provider/LocaleProviderAdapter' (0x000000080009b3c0)
[0.435s][info][class,init] 742 Initializing 'sun/util/locale/provider/LocaleProviderAdapter$Type' (0x000000080009b658)
[0.435s][info][class,init] 743 Initializing 'java/util/Collections$UnmodifiableList'(no method) (0x000000080009ba80)
loading: com.olympus.trade.util.TestLoading$BaseClassReturner...[0.435s][info][class,init] 744 Initializing 'java/util/Collections$UnmodifiableRandomAccessList'(no method) (0x000000080009bf50)

[0.435s][info][class,init] Start class verification for: com.olympus.trade.util.TestLoading$BaseClassReturner
[0.436s][info][class,init] 745 Initializing 'sun/util/locale/provider/JRELocaleProviderAdapter'(no method) (0x000000080009c620)
[0.436s][info][class,init] 746 Initializing 'java/lang/ReflectiveOperationException'(no method) (0x0000000800004028)
[0.436s][info][class,init] 747 Initializing 'sun/util/locale/provider/FallbackLocaleProviderAdapter' (0x000000080009c900)
[0.436s][info][class,init] 748 Initializing 'java/lang/ClassNotFoundException'(no method) (0x0000000800004288)
[0.436s][info][class,init] 749 Initializing 'java/lang/LinkageError'(no method) (0x00000008000044f8)
[0.436s][info][class,init] 750 Initializing 'java/lang/NoClassDefFoundError'(no method) (0x0000000800004758)
[0.436s][info][class,init] Verification for com.olympus.trade.util.TestLoading$BaseClassReturner has exception pending 'java.lang.NoClassDefFoundError com/olympus/trade/util/TestLoading$ChildClass'
[0.436s][info][class,init] End class verification for: com.olympus.trade.util.TestLoading$BaseClassReturner
[0.436s][info][class,init] 751 Initializing 'java/lang/Throwable$PrintStreamOrWriter'(no method) (0x000000080009cec0)
[0.436s][info][class,init] 752 Initializing 'java/lang/Throwable$WrappedPrintStream'(no method) (0x000000080009d0d8)
[0.436s][info][class,init] 753 Initializing 'sun/util/locale/LanguageTag' (0x000000080009d308)
java.lang.NoClassDefFoundError: com/olympus/trade/util/TestLoading$ChildClass[0.436s][info][class,init] 754 Initializing 'java/util/Collections$EmptyIterator' (0x000000080009d550)

您的代码在

BaseClassReturner.class.getName()
时失败,或者更准确地说,当您尝试访问
BaseClassReturner.class
时。如果您在该行的调试点停止并尝试评估
BaseClassReturner.class
,它将打印到控制台以下行:

[268.399s][info][class,init] Start class verification for: com.olympus.trade.util.TestLoading$BaseClassReturner
[268.401s][info][class,init] Verification for com.olympus.trade.util.TestLoading$BaseClassReturner has exception pending 'java.lang.NoClassDefFoundError com/olympus/trade/util/TestLoading$ChildClass'
[268.401s][info][class,init] End class verification for: com.olympus.trade.util.TestLoading$BaseClassReturner

JVM 在返回其实例之前开始验证该类,但它显然失败了,因为它在其主体中引用了

ChildClass
,此时您的代码已将其删除。

© www.soinside.com 2019 - 2024. All rights reserved.