如何避免Java中未使用的代码抛出的NoclassDeffoundError

 2023-01-20    260  

问题描述

我正在进行的项目是支持两个不同平台的API.在运行时,实际上只有两个平台中的一个将在ClassPath上可用.

在大多数情况下,我很容易编写这样的代码

如何避免Java中未使用的代码抛出的NoclassDeffoundError

if (isPlatformOne()) {
    PlatformOne.doSomething();
}

即使在运行时不存在PlatformOne,该检查事先意味着代码未运行,也不会丢弃错误.该技术适用于绝大多数情况,但是有一种情况我已经遇到了错误的地方.

如果PlatformOne也实现了不存在的接口,并且与也不存在的参数一起使用,那么当加载包含类时,无论代码是否实际执行,NoClassDefFoundError都会立即抛弃.

这是一个示例:

接口:

public interface DeleteInterface {

    void test(DeleteInterface delete);

}

类:

public class DeleteClass implements DeleteInterface {

    @Override
    public void test(DeleteInterface delete) {
    }

}

主:

public class Test {

    private final boolean test; //Cannot be constant or compiler will erase unreachable code

    public Test() {
        test = false;
    }

    public static void main(String[] args) {
        if (new Test().test) {
            DeleteClass c = new DeleteClass();
            c.test(c);
        }

        System.out.println("SUCCESS!");
    }

}

删除DeleteClass和DeleteInterface从罐子中产生以下错误:

A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: com/kmecpp/test/DeleteInterface
        at java.lang.Class.getDeclaredMethods0(Native Method)
        at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
        at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
        at java.lang.Class.getMethod0(Class.java:3018)
        at java.lang.Class.getMethod(Class.java:1784)
        at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
        at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
Caused by: java.lang.ClassNotFoundException: com.kmecpp.test.DeleteInterface
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ... 7 more

为什么仅针对这种特定情况会出现错误,而在不访问任何目标平台的代码的情况下,最佳的工作方式是什么?

推荐答案

Java验证器可能会因为必须存在其他验证,例如必须存在其他验证,例如必须存在NoClassDefFoundError,还必须在启动时通过JRE扫描的主类,此外还可以做到这一点.请参阅堆栈跟踪.
移动需要不存在代码的代码到其他类,然后在您要使用它的位置,请先检查该类是否存在,然后从该额外类中调用方法:

class MyExtraClass {
    public static void doStuff() {
        DeleteClass c = new DeleteClass();
        c.test(c);
    }
}

public boolean checkForClass(String className) {
    try  {
        Class.forName(className);
        return true;
    }  catch (ClassNotFoundException e) {
        return false;
    }
}

// somewhere in your code
if (checkForClass("package.DeletedClass")) {
    MyExtraClass.doStuff();
}

这只是此类情况的最安全选项,同样,如果这是非常短的代码,您可以使用一些本地类:(但在大多数情况下看起来并不好)

)

// somewhere in your code
if (checkForClass("package.DeletedClass")) {
    new Runnable() {
        @Override
        public void run() {
            DeleteClass c = new DeleteClass();
            c.test(c);
        }
    }.run();
}

其他推荐答案

我今天实际上遇到了这个问题.

确保您没有在系统类加载程序中两次加载同一类.

i.

我将代理引用中的名称更改为与前端引用不同,并且错误停止.

其他推荐答案

删除deleteclass和deleteinterface从jar产生
运行时的以下错误:

如果运行时不存在所需的类,则肯定会被抛弃.

即使PlatformOne在运行时不存在,也要事先进行检查
表示代码不运行,也不会丢弃错误.

请检查您的代码是否消除了错误的错误,如果是,您的应用不会崩溃并可以按正常执行.例如.下面的代码片段将抛出NoClassDefFoundError,但不会崩溃,因为您会消化错误.

public bool isPlatformOne() {
    try  {
        ...
        return true;
    }  catch (ClassNotFoundException e) {
       return false;
    }
}

如果您的用例仅是为了检查特定类是否存在,则可以使用Class.forName检查课程的存在.例如.

// className is the fully qualified class name. 
public boolean hasClass(String className) {
    try  {
        Class.forName(className);
        return true;
    }  catch (ClassNotFoundException e) {
        return false;
    }
}

在代码中使用它的示例.

if (hasClass("android.support.v7.app.AppCompatActivity")) {
    ...
}

以上所述是小编给大家介绍的如何避免Java中未使用的代码抛出的NoclassDeffoundError,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!

原文链接:https://77isp.com/post/26011.html

=========================================

https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。