NoSuchFieldError Java

时间:2011-07-13 23:09:19

标签: java debugging

我在我的代码中得到NoSuchFieldError,现在oracle不清楚为什么抛出这个错误只是说:如果类的定义发生了不兼容的改变,这个错误只能在运行时发生。< / em>的

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

7 个答案:

答案 0 :(得分:58)

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

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

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

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

答案 1 :(得分:7)

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

在运行时,另一个类以某种方式没有具有此名称的字段,这会导致提到的错误。

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

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

答案 2 :(得分:4)

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

示例:

project1取决于project2project3

project3取决于project2.jar,这是从project2

中的类文件生成的jar

最终的静态字段被添加到project2中的一个类中,该类被重新编译, 而project2.jar未重建

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

答案 3 :(得分:3)

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

例如:

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并且不是 MyDependingClass,那么当您运行程序并创建MyDependingClass实例时,您将获得 NoSuchFieldError

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

长期修复是使用Eclipse或NetBeans或其他为您处理此问题的IDE。

答案 4 :(得分:0)

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

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

几个小时后,我以某种方式在终端上检查了 javac -version 并猜到了它被设置为版本9。所以请确保查找javac,我知道它与直觉相反,但是据推测,因为我在bash配置文件,IntelliJ等上设置了jdk,我不必理会它。

希望有帮助!

答案 5 :(得分:0)

了解此错误:

这是一个java.lang.LinkageError错误,当jvm尝试链接已加载的类时发生。请注意,首先编译代码(使用相关类),然后由jvm加载所有涉及的类,然后将这些类链接在一起。

考虑错误:NoSuchField,这意味着在链接目标类时,该字段不存在。但是在编译时,该类应具有该字段,否则代码将无法编译。链接后,jvm会发现该字段不存在。因此,唯一的原因是我们正在使用具有该字段的类进行编译,并且已加载并链接了该类的另一个版本(不具有该字段)。


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

通常,错误加载的类要么是您已修改的源代码,要么是您的相关jar包中的一个类。我们可以通过将-verbose:class参数添加到试图运行您的应用程序的jvm中来找到错误加载的类,从而决定这一点。此参数显示控制台中所有已加载的类。在Eclipse中,我们将其放置在:右键单击您的项目->运行方式->运行配置-> arguments标签-> VM arguement字段。

找到错误加载的类后,通常它是您的项目中包含源代码的类,或者是您的项目所依赖的jar包中的类。 不同的情况导致不同的解决方案。


源代码案例的解决方案:

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


罐子包装盒的解决方案:

您应该尝试让项目加载正确的jar包。但是为什么要使用不同版本的原因通常是因为它们都依赖于(取决于项目的不同部分)。情况很简单(在现实世界的项目中可能不存在),如果您编写的代码直接取决于它们两者,则只需选择一个然后放下另一个即可。

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

一种解决方案是您编写自己的ClassLoader以同时满足以下两个条件:Possible to use two java classes with same name and same package?(我没有尝试过)

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

例如,以月食为例,您可以在Order and Export属性中使用Java Build Path标签,只需调整顺序即可使正确的版本领先于wrong版本,因为该功能Order部分中的是:

  

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

如果此处没有显示正确的版本或错误的版本,则由于Export part的功能,您应确定所依赖的软件包并调整其顺序。阅读The "Order and Export" tab in "Java Build Path"了解详情。

答案 6 :(得分:0)

尽管根本原因与最前面的答案中所述的相同,但我的问题与我在此处找到的其他答案有些不同,所以我认为我会分享。

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

解决方案是将每次出现的此依赖关系更新为相同的版本号。附带说明一下,为防止再次发生这种情况,我们在此处添加了一个变量,现在我们从一个位置控制那些依赖项的版本号。