NoSuchFieldError Java

Posted

技术标签:

【中文标题】NoSuchFieldError Java【英文标题】: 【发布时间】:2022-01-22 13:38:44 【问题描述】:

我的代码中出现 NoSuchFieldError,现在 oracle 不太清楚为什么会抛出此错误,只是说:如果类的定义发生不兼容的更改,此错误只会在运行时发生。

有人可以向我解释如何“不兼容地改变”一个班级吗?我正在谈论的课程扩展了很多课程,所以我怀疑它可能与此有关,但我不知道从哪里开始寻找或我在寻找什么。

【问题讨论】:

如果您包含堆栈跟踪或只是提示您尝试执行的操作,这可能会有所帮助。 好吧,我有一个名为 LuaUserdata 的类,它表示一个 Lua Userdata 值(你可以忘记 lua,它不相关)这个类有一个名为 m_metatable 的字段,LuaUserdata 由类 'a' 扩展,' a' 由'b' 扩展,最终由'Part' 扩展'e' 类。当我尝试访问“部分”中的字段 m_metatable 时,出现此错误,这很奇怪,因为该字段在 a、b 等类中没有被访问一次,并且所有扩展“d”的类仍然可以访问该字段. 【参考方案1】:

如果您只重新编译部分代码,通常会引发此错误。您的旧代码引用了重新编译的类文件中不再存在的字段。

解决方案是清除所有类文件并重新编译所有内容。

更新:如果您在重新编译所有内容后仍然遇到相同的错误,那么您可能是针对外部库的一个版本进行编译并在运行时使用另一个版本。

您现在需要做的是首先确定导致问题的类(看起来您已经这样做了),然后使用-verbose:class 命令行选项运行您的应用程序。它将在您的标准输出中转储大量类加载信息,您将能够找出问题类的确切加载位置。

【讨论】:

我按照你说的做了并清理/重新编译了,但恐怕它没有解决任何问题 是的,当我评论 Paŭlo 的回答时,我试图覆盖图书馆的某些类,我想这很麻烦。关于替换库的特定类而不必重建整个库的任何建议?我不能只是扩展它们,因为我还需要它们扩展一些东西。 如果您使用相同的 jars 编译和运行应用程序(并且它们的顺序相同),则不应出现此错误。您现在需要做的是首先确定导致问题的类(看起来您已经这样做了),然后使用-verbose:class 命令行选项运行您的应用程序。它将在您的标准输出中转储大量类加载信息,您将能够找出问题类的确切加载位置。 ... 你应该从你的类路径中删除有问题的 jar,这应该确保另一个(正确的)副本将被拾取。 正如@biziclop 所说,mvn clean install 就足够了【参考方案2】:

当编译器编译抛出错误的代码时,有一些其他类具有字段,您的类可以访问该字段(读取或更改值)。

在运行时,其他类不知何故没有具有此名称的字段,从而导致上述错误。

一个原因可能是第二个类在没有重新编译第一个类的情况下发生了变化。 重新编译你所有的类,你应该得到一个编译器错误(这会给你更多关于如何解决这个问题的信息),或者这个类将引用正确的类。

另一个原因可能是您在类路径(不同版本)中的多个 jar 文件(或目录)中有一些类,导致其他一些类使用了错误的类。检查重复类的所有 jar。

【讨论】:

您的第二个原因很可能是我的问题,因为我试图覆盖库的某些类。【参考方案3】:

在 IDE(在我的例子中是 Eclipse)中跟踪这些错误时需要注意的一点是观察您的项目可能依赖的项目的依赖关系。如果您在不同的依赖项目中使用不同版本的库,则类路径加载器可能会选择错误的库。这包括让一个项目依赖于从 Eclipse 项目创建的 jar,以及让另一个项目依赖于该项目和生成 jar 的项目。 jar 中过时的类可能会被加载,而不是项目中的类。

示例:

project1 依赖于 project2project3

project3 依赖于project2.jar,一个从project2 中的类文件生成的jar

project2中的一个类中添加一个final的静态字段,重新编译, 而project2.jar 没有重建

运行project1 可能会导致异常,因为project2 中的类可以直接从项目或没有该字段的jar 中加载

【讨论】:

这正是我现在在我的项目中所拥有的。现在我知道去哪里找了。你是我的救星,谢谢。 嗨。您需要检查项目订单导入。我有两个具有相同类名的项目。谢谢【参考方案4】:

这意味着您可能已经重新编译了一个由另一个已编译的类所依赖的类 - 而不是重新编译依赖的类。

例如:

public class MyClass 
    public int num;
    public MyClass()  num = 1; 


public class MyDependingClass 
    private int foo;
    public MyDependingClass(MyClass init) 
        foo = init.num;
    

所以你重新编译这两个类,大概是手动的(IDE 通常会为你更新项目工作区,以便处理依赖的类)。

它奏效了。

后来你决定重构 MyClass:

public class MyClass 
    private int innernum;
    public int getNum() 
        return innernum;
    
    public MyClass()  innernum = 1; 

如果你编译 MyClass 而 not MyDependingClass,当你运行你的程序并创建一个 MyDependingClass 的实例时,你会得到 NoSuchFieldError

短期修复可能是重新编译工作区中的所有类,这应该会显示错误。

长期解决方案是使用 Eclipse 或 NetBeans 或其他为您处理此问题的 IDE。

【讨论】:

我正在使用 NetBeans 并重新编译了所有内容,但没有任何改变【参考方案5】:

虽然根本原因与热门答案中描述的相同,但我的问题与我在这里找到的其他答案有点不同,所以我想我会分享。

我正在从事一个大型项目,该项目在整个项目中分布着多个 maven pom。一位同事更新了其中一个依赖项的版本号,而没有更新出现该依赖项的每个位置,从而导致类路径上的库不匹配。

解决方案是将此依赖项的每次出现都更新为相同的版本号。作为旁注,为了防止这种情况再次发生,我们在那里添加了一个变量,现在我们从一个位置控制这些依赖项的版本号。

【讨论】:

【参考方案6】:

这对我来说很棘手,所以我正在编写我的解决方案。

我在 IntelliJ 中使用 Boot 一切都很好,所有 Java 8 版本都已正确设置。

几个小时后,我以某种方式在终端上检查了 javac -version 并猜猜是什么,它被设置为版本 9。所以一定要寻找 javac,我知道它违反直觉,但据说,因为我已经在 bash 配置文件、IntelliJ 等上设置了 jdk,我不应该打扰它。

希望对你有帮助!

【讨论】:

我不认为是java版本的问题,既然有字段,任何版本的jdk都不会丢失。【参考方案7】:

了解此错误:

这是一个java.lang.LinkageError 错误,当 jvm 尝试链接加载的类时发生。注意代码是先编译的(和依赖的类),然后所有涉及的类都被jvm加载,然后这些类链接在一起。

想想错误:NoSuchField,表示链接目标类时,字段不存在。但是在编译时,类应该有那个字段,否则代码无法编译。链接后,jvm 发现该字段不存在。所以唯一的原因是我们正在使用具有该字段的类进行编译,并且加载并链接了该类的另一个版本(没有该字段)。


在导致此错误的两个常见原因之间确定您的情况

通常错误加载的类要么是你修改过的源代码,要么是你依赖的 jar 包中的一个类。我们可以通过将-verbose:class 参数添加到试图在您的ide 中运行您的应用程序的jvm 来查找错误加载的类来决定这一点。此参数在控制台中打印所有加载的类。在eclipse中,我们将它放置在:右键单击您的项目->运行方式->运行配置->arguments标签->VM argument字段。

找到错误加载的类后,通常要么是你项目中有源代码的类,要么是你的项目所依赖的jar包。 不同的情况导致不同的解决方案。


源码案例解决方案:

您可能更改了该类(在源代码中添加了该字段),但没有重新编译它。可能由于不同的原因,但是你应该删除旧版本编译的那个类的.class文件,然后重新编译它,让新版本的.class文件包含那个字段。


jar包案例解决方案:

你应该尽量让项目加载正确的jar包。但是为什么要使用不同的版本通常是因为它们都依赖(由项目的不同部分)。情况很简单(现实世界的项目中可能不存在),如果你写的代码直接依赖于它们两者,只需要选择一个并丢弃另一个。

但您的代码可能间接依赖于它们。而且您不想更改代码(或尽可能少更改)。

一种解决方案是您自己编写ClassLoader 来同时使用:Possible to use two java classes with same name and same package?(我没有尝试过)

如果您选择加载正确的版本(包含这样的field),并且您的代码间接依赖于wrong 版本仍然可以工作(希望如此),那么我们有一个非常简单的解决方案:让您的项目选择正确的版本。

以eclipse为例,你可以在Java Build Path属性中使用Order and Export 标签,只需调整顺序让正确的版本在wrong版本之前,因为Order部分的功能是:

一方面,它充当资源的解析顺序 用于构建相关项目(“订单”部分)。

如果那里没有显示正确的版本或错误的版本,您应该根据Export part 的功能确定它是什么包并调整其顺序。阅读The "Order and Export" tab in "Java Build Path"了解详情。

【讨论】:

以上是关于NoSuchFieldError Java的主要内容,如果未能解决你的问题,请参考以下文章

获取 java.lang.NoSuchFieldError: RamlValidationService 中的值

春天:java.lang.NoSuchFieldError:IMPORT_BEAN_NAME_GENERATOR

java.lang.NoSuchFieldError:INSTANCE

java.lang.NoSuchFieldError: TRACE

线程“主”java.lang.NoSuchFieldError 中的异常:如果可能

Hibernate java.lang.NoSuchFieldError: INSTANCE