“找不到符号”或“无法解析符号”错误是什么意思?


396

请解释以下有关“找不到符号”和“无法解析符号”错误的信息:

  • 他们的意思是什么?
  • 什么事会导致它们?
  • 程序员如何进行修复?

该问题旨在对Java中的这些常见编译错误进行全面的问答。

Answers:


417

0.两种错误之间有区别吗?

并不是的。“找不到符号”和“无法解析符号”含义相同。一些Java编译器使用一个短语,而另一些使用。

1.“找不到符号”错误是什么意思?

首先,它是编译错误1。这意味着,无论有在Java源代码中的问题,有在你编译它的方式有问题。

您的Java源代码包含以下内容:

  • 关键词:喜欢truefalseclasswhile,等。
  • 文字:like 42'X'and "Hi mum!"
  • 运营商和其他非字母数字标记:像+={,等等。
  • 标识符:喜欢ReaderitoStringprocessEquibalancedElephants,等。
  • 注释和空格。

“找不到符号”错误与标识符有关。编译代码时,编译器需要确定代码中每个标识符的含义。

“找不到符号”错误表示编译器无法执行此操作。您的代码似乎是指编译器无法理解的内容。

2.什么会导致“找不到符号”错误?

首先,只有一个原因。编译器查看了应该定义标识符的所有位置,但找不到该定义。这可能是由多种原因引起的。常见的如下:

  • 对于一般的标识符:
    • 也许您拼错了名字;即StringBiulder代替StringBuilder。Java无法也不会尝试弥补拼写错误或输入错误。
    • 也许你错了。即stringBuilder代替StringBuilder。所有Java标识符均区分大小写。
    • 也许您不恰当地使用了下划线;即mystringmy_string不同。(如果您坚持使用Java样式规则,则将在很大程度上避免出现此错误...)
    • 也许您正在尝试使用被声明为“其他地方”的东西;即在与您隐式告诉编译器查看的位置不同的上下文中。(不同的类?不同的作用域?不同的包?不同的代码库?)
  • 对于应引用变量的标识符:
    • 也许您忘记了声明变量。
    • 变量声明在您尝试使用它时可能超出范围。(请参见下面的示例)
  • 对于应为方法或字段名称的标识符:

    • 也许您正在尝试引用在父/祖先类或接口中未声明的继承方法或字段。
    • 也许您正在尝试引用所使用的类型中不存在(即尚未声明)的方法或字段;例如"someString".push()2
    • 也许您正在尝试将方法用作字段,反之亦然;例如"someString".lengthsomeArray.length()
    • 也许您是错误地对数组而不是数组元素进行操作。例如

      String strings[] = ...
      if (strings.charAt(3)) { ... }
      // maybe that should be 'strings[0].charAt(3)'
      
  • 对于应为类名的标识符:

    • 也许您忘记了导入课程。
    • 也许您使用了“星号”导入,但是在您导入的任何软件包中均未定义该类。
    • 也许您忘记了new

      String s = String();  // should be 'new String()'
  • 对于类型或实例似乎没有成员的情况,您希望它具有:

    • 也许您已经声明了一个嵌套类或泛型参数,该类掩盖了您打算使用的类型。
    • 也许您正在隐藏静态变量或实例变量。
    • 也许您输入了错误的类型;例如由于IDE完成或自动更正。
    • 也许您正在使用(针对)错误版本的API。
    • 也许您忘记了将对象转换为适当的子类。

问题通常是上述情况的组合。例如,也许您导入了“ star” java.io.*,然后尝试使用Filesclass中的java.nionot java.io。或者也许你打算写File... ...这是的一个类java.io


这是一个示例,说明变量作用域范围不正确会如何导致“找不到符号”错误:

List<String> strings = ...

for (int i = 0; i < strings.size(); i++) {
    if (strings.get(i).equalsIgnoreCase("fnord")) {
        break;
    }
}
if (i < strings.size()) {
    ...
}

这将使“无法找到符号”错误iif陈述。虽然我们先前声明i,该声明只是在范围上for发言和它的身体。语句i中对的引用看不到的声明。它超出范围ifi

(这里的一个适当的更正可能是将if语句移入循环内部,或者i在循环开始之前进行声明。)


这是一个引起困惑的示例,其中的错字导致看似莫名的“找不到符号”错误:

for (int i = 0; i < 100; i++); {
    System.out.println("i is " + i);
}

这将在println呼叫中给您一个编译错误,提示i找不到。但是(我听到你说)我确实宣布了!

问题是冒号;前的冒号(){。Java语言语法在该上下文中将分号定义为空语句。空语句然后成为for循环的主体。因此,该代码实际上意味着:

for (int i = 0; i < 100; i++); 

// The previous and following are separate statements!!

{
    System.out.println("i is " + i);
}

{ ... }块不是for循环的主体,因此ifor语句中的先前声明超出了该块的范围


这是由错字引起的“找不到符号”错误的另一个示例。

int tmp = ...
int res = tmp(a + b);

尽管与先前的声明中,tmptmp(...)表达是错误的。编译器将寻找一种称为的方法tmp,但找不到。先前声明tmp的变量位于名称空间中,而不是方法的名称空间中。

在我遇到的示例中,程序员实际上省略了一个运算符。他的意思是这样写的:

int res = tmp * (a + b);

如果从命令行进行编译,则编译器可能找不到符号还有另一个原因。您可能只是忘了编译或重新编译其他类。例如,如果您有类,Foo并且Bar在哪里Foo使用Bar。如果您从未编译过Bar并且运行过javac Foo.java,您很有可能发现编译器找不到该符号Bar。简单的答案是编译FooBar在一起; 例如javac Foo.java Bar.javajavac *.java。或者最好还是使用Java构建工具;例如Ant,Maven,Gradle等。

还有一些其他更晦涩的原因...我将在下面处理。

3.如何解决这些错误?

一般来说,首先要弄清楚是什么导致了编译错误。

  • 查看编译错误消息指示的文件中的行。
  • 确定错误消息正在谈论的符号。
  • 弄清楚编译器为什么说找不到符号;为什么?往上看!

然后,您考虑一下您的代码应该说什么。然后,最后您确定需要对源代码进行哪些更正以执行所需的操作。

请注意,并非每个“更正”都是正确的。考虑一下:

for (int i = 1; i < 10; i++) {
    for (j = 1; j < 10; j++) {
        ...
    }
}

假设编译器为表示“找不到符号” j。我可以通过多种方式“修复”该问题:

  • 我可以将内部更改forfor (int j = 1; j < 10; j++)-可能是正确的。
  • 我可以在内部循环或外部循环j 之前添加一个声明-可能正确。forfor
  • 我可以更改jifor循环-可能是错误的!
  • 等等。

关键是您需要了解您的代码正在尝试做什么才能找到正确的修复程序。

4.不明原因

在一些情况下,“找不到符号”似乎无法解释……直到您仔细观察。

  1. 不正确的依赖关系:如果您使用的是IDE或管理构建路径和项目依赖关系的构建工具,则可能是错误的依赖关系。例如遗漏了一个依赖项,或者选择了错误的版本。如果您使用的是构建工具(Ant,Maven,Gradle等),请检查项目的构建文件。如果使用的是IDE,请检查项目的构建路径配置。

  2. 您无需重新编译:有时候,新Java程序员可能不了解Java工具链的工作方式,或者没有实现可重复的“构建过程”;例如使用IDE,Ant,Maven,Gradle等。在这种情况下,程序员最终可能会追尾寻找一个虚幻的错误,该错误实际上是由于未正确地重新编译代码而导致的,等等。

  3. 较早的构建问题较早的构建可能会失败,从而导致JAR文件缺少类。如果使用构建工具,通常会注意到这种故障。但是,如果要从其他人那里获取JAR文件,则取决于它们是否可以正确构建并注意到错误。如果您怀疑这一点,请使用tar -tvf列出可疑JAR文件的内容。

  4. IDE问题:人们已经报告了他们的IDE混乱并且IDE中的编译器找不到存在的类的情况……或相反的情况。

    • 如果IDE配置了错误的JDK版本,则可能会发生这种情况。

    • 如果IDE的缓存与文件系统不同步,则可能发生这种情况。有特定于IDE的方法可以解决此问题。

    • 这可能是一个IDE错误。例如,@ Joel Costigliola描述了Eclipse无法正确处理Maven“测试”树的情况:请参见此答案

  5. Android问题:在为Android编程时,您遇到与相关的“找不到符号”错误R,请注意,R符号是由context.xml文件定义的。检查您的context.xml文件正确且正确的位置,以及相应的R类文件是否已生成/编译。请注意,Java符号区分大小写,因此相应的XML ID也区分大小写。

    Android上的其他符号错误可能是由于前面提到的原因引起的;例如,缺少或不正确的依赖项,不正确的程序包名称,在特定API版本中不存在的方法或字段,拼写/键入错误等。

  6. 重新定义系统类:我看到过这样的情况,编译器substring在以下情况中抱怨说这是一个未知符号

    String s = ...
    String s1 = s.substring(1);
    

    事实证明,程序员创建了自己的版本,String而他的类版本未定义substring方法。

    课程:不要用与通用库类相同的名称定义自己的类!

  7. 同源符号: 如果对源文件使用UTF-8编码,则可能具有看起来相同但实际上不同的标识符,因为它们包含同源符号。有关更多信息,请参见此页面

    通过将自己限制为ASCII或Latin-1作为源文件编码,并对\uxxxx其他字符使用Java 转义,可以避免这种情况。


1 -如果,或许,你看到这个运行时异常或错误信息,那么无论你配置你的IDE来运行代码编译错误,或者您的应用程序生成和编译代码..在运行时。

2-土木工程的三个基本原则:水不上坡,木板在其侧面更坚固,并且您不能用力压绳子


我还有另一种情况,当eclipse没看到问题时发生了此编译错误:两个类分别在另一个类中定义了依赖项。在我的情况下,我有一个枚举,实现了一个接口,该接口在我愚蠢地已经使用了该枚举的类中定义。
Jogi,2016年

与上面的注释有点类似,当我从Eclipse编译并运行程序时,它没有问题。从控制台进行编译会引发许多此类“找不到符号”错误,这些错误通常与导入中的最后一个元素有关。我不知道是什么原因造成的,因为代码中没有任何错误。
安德烈斯·斯塔德曼

另一个问题是,IDE可能会将其他错误“解释”为此类。例如printlnSystem.out.println如果放在标准编译器的类级别下,将给我们<identifier> expecteddemo),但在IntelliJ中,我们将看到Cannot resolve symbol 'println'demo)。
Pshemo

哇。我将其称为编译器错误。
斯蒂芬·C

23

如果您忘记了new:,也会出现此错误:

String s = String();

String s = new String();

因为没有new关键字的调用将尝试查找String没有参数的(本地)方法-而且该方法签名可能未定义。


14

“变量超出范围”的另一个示例

正如我已经看过几次这样的问题一样,即使感觉还可以,也许还有另一个例子说明违法行为。

考虑以下代码:

if(somethingIsTrue()) {
  String message = "Everything is fine";
} else {
  String message = "We have an error";
}
System.out.println(message);

那是无效的代码。因为命名的变量message在它们各自的作用域之外都不可见- {}在这种情况下,将用括号括起来。

您可能会说:“但是以任何一种方式都定义了一个名为message的变量-因此message if“ 之后定义的。

但是你会错的。

Java没有free()delete运算符,因此它必须依赖于跟踪变量范围来确定何时不再使用变量(以及对这些cause变量的引用)。

如果您认为自己做得很好,那就特别糟糕。在“优化”如下代码后,我已经看到这种错误:

if(somethingIsTrue()) {
  String message = "Everything is fine";
  System.out.println(message);
} else {
  String message = "We have an error";
  System.out.println(message);
}

“哦,有重复的代码,让我们拉出这条共同的线”->到那里。

处理这种范围问题的最常见方法是将else值预先分配给外部范围中的变量名,然后在以下情况下重新分配:

String message = "We have an error";
if(somethingIsTrue()) {
  message = "Everything is fine";
} 
System.out.println(message);

4
“ Java没有free()或delete运算符,因此它必须依靠跟踪变量范围来找出何时不再使用变量(以及对这些cause变量的引用)。” -虽然正确,但这无关紧要。C和C ++分别具有free / delete运算符,但是与您的示例等效的C / C ++代码将是非法的。就像Java中一样,C和C ++块限制了变量的范围。实际上,对于大多数“块结构”语言来说都是如此。
斯蒂芬C

1
对于在每个分支上分配不同值的代码,更好的解决方案是使用空白final变量声明。
丹尼尔·普里登

10

在Eclipse中获得此错误的一种方法:

  1. 定义一个类Asrc/test/java
  2. 定义另一个类Bsrc/main/java使用类A

结果:Eclipse将编译代码,但是maven将给出“找不到符号”。

潜在原因:Eclipse对主树和测试树使用了组合的构建路径。不幸的是,它不支持为Eclipse项目的不同部分使用不同的构建路径,而这正是Maven所需要的。

解决方案:

  1. 不要以这种方式定义依赖项;即不要犯这个错误。
  2. 定期使用Maven构建代码库,以便您尽早发现此错误。一种方法是使用CI服务器。

这个解决方案是什么?

2
您在src / main / java中使用的任何内容都必须在src / main / java或任何编译/运行时依赖项中定义(而不是测试依赖项)。
Joel Costigliola

5

“找不到”表示编译器找不到合适的变量,方法,类等...如果您遇到错误提示,首先您要找到获取错误提示的代码行。然后,您将找到能够在使用之前找到尚未定义的变量,方法或类。确认初始化后,该变量,方法或类可用于以后的需求...请考虑以下示例。

我将创建一个演示类并打印一个名称...

class demo{ 
      public static void main(String a[]){
             System.out.print(name);
      }
}

现在看一下结果。

在此处输入图片说明

该错误表示“找不到变量名”。可以取消为“ name”变量定义和初始化值的错误。实际上,

class demo{ 
      public static void main(String a[]){

             String name="smith";

             System.out.print(name);
      }
}

现在看看新的输出...

在此处输入图片说明

好的,成功解决了该错误。同时,如果您得到“找不到方法”或“找不到类”的东西,请首先定义一个类或方法,然后再使用它。


3

如果您在其他地方的构建中遇到此错误,而您的IDE表示一切都很好,请检查两个地方是否使用相同的Java版本。

例如,Java 7和Java 8具有不同的API,因此在较旧的Java版本中调用不存在的API会导致此错误。


2

我也收到此错误。(我为此搜索了Google,并将其定向到此页面)

问题:我正在从另一个项目B中定义的类中调用在项目A的类中定义的静态方法。出现以下错误:

error: cannot find symbol

解决方案:我首先通过建立定义方法的项目,然后再从其中调用方法的项目来解决此问题。


是的,例如,如果您决定将一些可重用的函数从当前程序包移至公共utils程序包,则可能会发生这种情况,但随后您忘记了在从当前程序包调用函数之前编译公共程序包。
buildingKofi

2

如果将eclipse Java构建路径映射到7、8,并且在Project pom.xml Maven属性中提到java.version的Java版本高于(9、10、11等),则需要在pom中进行更新,而不是7,8。 xml文件。

在Eclipse中,如果Java映射到Java版本11,而在pom.xml中,则映射到Java版本8,请通过执行Eclipse IDE帮助->安装新软件->中的以下步骤,将Eclipse支持更新为Java 11。

工作时粘贴以下链接http://download.eclipse.org/eclipse/updates/4.9-P-builds

要么

添加(将打开弹出窗口)->

Name:Java 11支持 Location: http://download.eclipse.org/eclipse/updates/4.9-P-builds

然后如下所示更新pom.xml文件的Maven属性中的Java版本

<java.version>11</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>

最后,右键单击项目Debug as-> Maven clean,Maven构建步骤



1

正如上面人们所提到的,可能有各种情况。有几件事帮助我解决了这个问题。

  1. 如果您使用的是IntelliJ

    File -> 'Invalidate Caches/Restart'

要么

  1. 被引用的类在另一个项目中,并且该依赖项未添加到我项目的Gradle构建文件中。所以我使用添加了依赖

    compile project(':anotherProject')

而且有效。HTH!


1

您使用maven compile编译了代码,然后使用maven测试运行了它。现在,如果您更改了代码中的某些内容,然后在不编译的情况下运行它,则会收到此错误。

解决方案:再次编译它,然后运行测试。对我来说,它是这样工作的。


1

就我而言-我必须执行以下操作:

  1. context.xml文件从移动src/java/packageresource目录(IntelliJ IDE)
  2. 清理target目录。

在不关心引用的情况下移动文件可能会导致此错误。我已经遇到了 只需在Git上重置并小心地再次移动,即可解决错误。
伊·洪姆(HuyHómHỉnh),

0

有关提示,请仔细查看引发错误的类名和行号,例如:编译失败[ERROR] \ applications \ xxxxx.java:[44,30]错误:找不到符号

另一个原因是Java版本不支持的方法,例如jdk7 vs8。检查您的%JAVA_HOME%


这和其他答案说的一样。
斯蒂芬·C
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.