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

2023-12-11

我正在从事的项目是一个支持两个不同平台的API。在运行时,类路径上实际上只有两个平台之一可用。

在大多数情况下,我很容易就能编写出这样工作正常的代码

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

Even if PlatformOne运行时不存在,预先检查意味着代码不会运行并且不会抛出错误。这种技术适用于大多数情况,但是我遇到过一种抛出错误的情况。

If PlatformOne还实现了一个不存在的接口并且与也不存在的参数一起使用,然后NoClassDefFoundError加载包含类时立即抛出,无论代码是否实际执行。

这是一个例子:

界面:

public interface DeleteInterface {

    void test(DeleteInterface delete);

}

Class:

public class DeleteClass implements DeleteInterface {

    @Override
    public void test(DeleteInterface delete) {
    }

}

Main:

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 and DeleteInterface从 jar 中生成的运行时会产生以下错误:

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();
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何避免 Java 中未使用的代码抛出 NoClassDefFoundError 的相关文章

随机推荐

  • 示例:使用 AsyncTask 的 Android 双向网络套接字

    我发现的大多数 Android 网络套接字示例都是单向的 我需要一个双向数据流的解决方案 我最终了解到了 AsyncTask 此示例演示如何从套接字获取数据并将数据发送回套接字 由于接收数据的套接字具有阻塞性质 因此该阻塞需要在 UI 线程
  • 如何让 Jenkins 上的 groovy 屏蔽变量的输出,就像处理凭证一样?

    Jenkins 上的 groovy 是否有一种方法可以获取任意字符串变量 例如对另一个服务的 API 调用的结果 并让 Jenkins 在控制台输出中屏蔽它 就像它自动从凭证管理器读取的值一样 更新的解决方案 要隐藏变量的输出 您可以使用掩
  • 声明与全局、局部和静态同名的变量

    我有以下代码片段 我必须分析输出是什么 include
  • 使用 Sunspot 从 Solr 索引中排除文章草稿

    我有一个名为 Article 的索引模型 我不希望 solr 索引未发布的文章 class Article lt ActiveRecord Base searchable do text title text body end end 我怎
  • Deviseomniauthable 因“无法找到有效的路径映射”而破坏 Omniauth 身份验证

    在我的项目中 我有两种类型的用户 求职者和招聘经理 求职者没有模型 他们只能使用从第三方提供商收到的数据来申请工作 同时通过 Omniauth 进行身份验证 招聘经理的信息存储在设计用户模型中 招聘经理还必须能够使用其公司的 Google
  • mysql where语句日期问题

    希望有人能帮忙 我想做的是从数据库中提取任何给定月份的所有结果 是否可以仅使用 mysql 查询 无 php 我使用一个模板应用程序 我唯一的访问权限是通过 mysql where 语句 所以我需要从 2013 04 01 算出月份是什么
  • 求解具有变量约束的非线性方程组

    使用 fsolve 求解非线性方程组的一些假设示例 from scipy optimize import fsolve import math def equations p x y p return x y 2 4 math exp x
  • 不使用主键的映射中流畅的 NHibernate 连接表

    我正在尝试从 2 个不通过主键相关的表创建一个实体 Tables CREATE TABLE employees ssn nvarchar 9 NULL active bit NULL employee id int IDENTITY 1 1
  • Android:如何制作带有 2 行文本和 RadioButton(单选)的 AlertDialog?

    如何制作包含如下行的列表对话框 FIRST LINE OF TEXT o lt this is a RadioButton second line of text 我知道我应该使用自定义适配器 通过这些视图传递行布局 实际上 我已经这样做了
  • 更新文档时出现错误:由于值未定义,转换为字符串失败

    我有一个简单的文档 其中包含名称 必需 和描述 可选 在我的模型中 我使用有效 ID 更新文档 并传递值为未定义的描述 因为我想从文档中删除此属性 但是 我收到以下错误 消息 转换为字符串失败 路径 描述 处的值 未定义 名称 CastEr
  • Magento:如何在客户信息字段中显示客户的电话号码

    我试图让客户的电话号码显示在客户帐户信息部分下 我知道电话号码属于客户地址部分 但我正在尝试重新设计客户帐户信息的外观 我为客户 ID 添加了一个新的自定义字段 并且可以使用以下代码显示它 因为客户 ID 属于 customer entit
  • 在 cakephp 中验证输入文件

    在 cakephp 中 我试图检查文件输入字段是否附加了文件 如果没有则输出错误 我已经在其他领域做到了这一点 但似乎无法让它在该领域发挥作用 这是模型 array notempty uploadeduploaded file gt arr
  • 将输入的数据存储在数组中[重复]

    这个问题在这里已经有答案了 我是 C 初学者 如果我的问题很蹩脚 请不要介意 在我编写的这个程序中 当我第一次使用 for 循环时 我预计数组中仅存储 3 个值 但它存储 4 个值 并且在下一个 for 循环中按预期显示 3 个值 我的问题
  • 如何避免触发器内的 ORA-04091 错误

    我在表 A 上有一个更新后触发器 触发器 A 可以对表 B 进行更改 我在表 B 上还有一个更新后触发器 触发器 B 它不进行任何更改 但查询表 A 以对非规范化进行一些健全性检查 因此触发器 B 可以通过以下两种方式之一触发 如果我直接更
  • 带重定向的 Node.js 包罗万象的路由始终使用 Angular 呈现索引页面,无论 url 是什么

    本质上当我使用包罗万象的路线并使用res redirect 无论我输入的网址如何 它总是会呈现索引 主页 即 Angular 似乎没有 看到 完整的网址 但是如果我放置res render index 在包罗万象的路线中一切正常 我不想重复
  • Python:静态变量装饰器

    我想创建一个如下所示的装饰器 但我似乎想不出可行的实现 我开始认为这是不可能的 但我想我应该先问你们 我意识到在 Python 中还有各种其他方法来创建静态变量 但我发现这些方法很丑陋 如果可能的话 我真的很想使用下面的语法 static
  • 如何查看 SQL Server Management Studio 编辑器中制表位的位置?

    我使用语音识别来听写 SQL 而将事情排列起来很痛苦 如果我能看到制表位在哪里 那会节省我很多时间 Management Studio 支持一项未记录的功能 Visual Studio 也有 它将垂直引导线添加到编辑器窗口的特定列位置 使用
  • 无法在 Linux 机器上通过 ODBC 连接到 informix

    我正在运行 CentOS 7 的虚拟机上工作 并且尝试通过一些 php 使用 ODBC unixODBC 连接到 Informix 数据库 我使用的是 php7 0 并且安装了 unixODBC 2 3 7 以及 informix sdk
  • 创建自定义 MutableState 持有者

    Compose 仅 允许有限数量的状态持有者 包括所有原始数据类型和一些额外的附加组件 但不支持自定义对象或任何更复杂的对象 例如Path 我希望确保对这些类型的更改也能很好地观察到 因此我想为这些类型实现自定义扩展 就像他们添加了muta
  • 如何避免 Java 中未使用的代码抛出 NoClassDefFoundError

    我正在从事的项目是一个支持两个不同平台的API 在运行时 类路径上实际上只有两个平台之一可用 在大多数情况下 我很容易就能编写出这样工作正常的代码 if isPlatformOne PlatformOne doSomething Even