“找不到符号”或“无法解析符号”错误是什么意思?0. 这些错误之间有什么区别吗?1. “找不到符号”错误是什么意思?2. 什么会导致“找不到符号”错误?3. 如何修复这些错误?4. 原因不明

请解释以下有关“找不到符号”、“无法解析符号”或“找不到符号”错误(在 Java 中)::

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

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


答案 1

0. 这些错误之间有什么区别吗?

没有。“找不到符号”,“无法解析符号”和“找不到符号”都意味着同样的事情。(不同的Java编译器是由不同的人编写的,不同的人使用不同的短语来表达同样的事情。

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

首先,它是编译错误1。这意味着您的Java源代码中存在问题,或者您的编译方式存在问题。

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

  • 关键字:如、、等。classwhile
  • 文字:如、、和 。truefalse42'X'"Hi mum!"
  • 运算符和其他非字母数字标记:如 、、、等。+={
  • 标识符:如 、、、等。ReaderitoStringprocessEquibalancedElephants
  • 注释和空格。

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

“找不到符号”错误意味着编译器无法执行此操作。您的代码似乎引用了编译器不理解的内容。

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

作为第一顺序,只有一个原因。编译器查找了定义标识符的所有位置,但找不到定义。这可能是由许多事情引起的。常见的有以下几种:

  • 对于一般的标识符:

    • 也许你拼错了名字;即 而不是。Java不能也不会试图弥补拼写错误或打字错误。StringBiulderStringBuilder
    • 也许你弄错了案子;即 而不是。所有 Java 标识符都区分大小写。stringBuilderStringBuilder
    • 也许你不恰当地使用了下划线;即 并且是不同的。(如果你坚持Java风格规则,你将在很大程度上受到保护,免受这个错误的影响......mystringmy_string
    • 也许您正在尝试使用被声明为“其他地方”的东西;即,在与隐式告诉编译器查看的上下文不同的上下文中。(不同的班级?不同的范围?不同的包装?不同的代码库?
  • 对于应引用变量的标识符:

    • 也许您忘记声明变量。
    • 也许变量声明在您尝试使用它时超出了范围。(请参阅下面的示例)
  • 对于应为方法或字段名称的标识符:

    • 也许您正在尝试引用未在父/祖先类或接口中声明的继承方法或字段。

    • 也许您正在尝试引用您正在使用的类型中不存在(即尚未声明)的方法或字段;例如 2."rope".push()

    • 也许您正在尝试使用方法作为字段,反之亦然;例如: 或。"rope".lengthsomeArray.length()

    • 也许你错误地操作了数组而不是数组元素;例如:

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

    • 也许您忘记导入该类。

    • 也许您使用了“star”导入,但该类未在您导入的任何包中定义。

    • 也许你忘了一个,如:new

          String s = String();  // should be 'new String()'
      
  • 对于类型或实例似乎没有您期望的成员(例如方法或字段)的情况:

    • 也许您已经声明了一个嵌套类或泛型参数,该参数将隐藏您要使用的类型。
    • 也许您正在隐藏静态变量或实例变量。
    • 也许您导入了错误的类型;例如,由于IDE完成或自动更正可能已经建议而不是。java.awt.Listjava.util.List
    • 也许您正在使用(编译)错误版本的API。
    • 也许您忘记将对象投射到适当的子类。
    • 也许您已经将变量的类型声明为具有您要查找的成员的变量类型的超类型。

问题通常是上述因素的组合。例如,也许您“星形”导入,然后尝试使用该类...这不是 .或者也许你打算写...这是 中的一个类。java.io.*Filesjava.niojava.ioFilejava.io


下面是一个示例,说明不正确的变量作用域如何导致“找不到交易品种”错误:

List<String> strings = ...

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

这将在语句中给出 “找不到交易品种” 错误。虽然我们之前声明过,但该声明只在声明及其主体的范围内。语句中对 的引用看不到 的声明。它超出了范围iififoriifi

(此处的适当更正可能是将语句移动到循环内部,或在循环开始之前声明。ifi


下面是一个引起困惑的例子,其中拼写错误导致看似莫名其妙的“找不到符号”错误:

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

这将在调用中为您提供一个编译错误,指出找不到该错误。但是(我听到你说)我确实宣布了!printlni

问题是 前面偷偷摸摸的分号 ( )。Java 语言语法将该上下文中的分号定义为空语句。然后,空语句将成为循环的主体。所以代码实际上是这样说的:;{for

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

// The previous and following are separate statements!!

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

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


下面是由拼写错误引起的“找不到符号”错误的另一个示例。

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

尽管有前面的声明,但表达式中的是错误的。编译器将查找名为 的方法,但找不到。以前声明的命名空间位于变量的命名空间中,而不是方法的命名空间中。tmptmp(...)tmptmp

在我遇到的例子中,程序员实际上遗漏了一个运算符。他想写的是:

int res = tmp * (a + b);

如果从命令行进行编译,则编译器可能无法找到符号还有另一个原因。您可能只是忘记编译或重新编译其他类。例如,如果您有类,并且其中使用 .如果你从来没有编译过,你运行过,你很容易发现编译器找不到符号。简单的答案是编译和组合;例如: 或。或者最好还是使用Java构建工具;例如蚂蚁,Maven,Gradle等。FooBarFooBarBarjavac Foo.javaBarFooBarjavac Foo.java Bar.javajavac *.java

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

3. 如何修复这些错误?

一般来说,您首先要找出导致编译错误的原因。

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

然后你想想你的代码应该说什么。最后,你弄清楚你需要对源代码进行哪些更正才能做你想做的事情。

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

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

假设编译器对 说“找不到符号”。我可以通过多种方式“修复”这些方法:j

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

关键是您需要了解代码尝试执行的操作才能找到正确的修复程序。

4. 原因不明

以下是“找不到符号”似乎莫名其妙的几个情况......直到你仔细观察。

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

  2. 找不到符号“var”:您可能正在尝试使用较旧的编译器或较旧的级别编译使用局部变量类型推断(即声明)的源代码。是在 Java 10 中引入的。检查 JDK 版本和生成文件,以及 IDE 设置(如果 IDE 中发生这种情况)。var--sourcevar

  3. 你没有编译/重新编译:有时会发生新的Java程序员不了解Java工具链是如何工作的,或者没有实现可重复的“构建过程”;例如,使用IDE,Ant,Maven,Gradle等。在这种情况下,程序员最终可能会追逐他的尾巴,寻找一个虚幻的错误,这个错误实际上是由于没有正确重新编译代码等引起的。

    另一个例子是当你使用(Java 9 +)编译和运行一个类时。如果该类依赖于您尚未编译(或重新编译)的另一个类,则可能会收到引用第二类的“无法解析符号”错误。其他源文件不会自动编译。该命令的新“编译并运行”模式不是为运行具有多个源代码文件的程序而设计的。java SomeClass.javajava

  4. 早期构建问题:早期构建可能以缺少类的 JAR 文件的方式失败。如果您使用的是构建工具,通常会注意到此类故障。但是,如果您从其他人那里获得JAR文件,则依赖于它们正确构建并注意到错误。如果您怀疑这一点,请使用 列出可疑 JAR 文件的内容。tar -tvf

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

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

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

    • 这可能是一个 IDE 错误。例如,@Joel Costigliola描述了一个Eclipse没有正确处理Maven“测试”树的场景:请参阅此答案。(显然,这个特定的错误很久以前就已经修复了。

  6. Android 问题:当您为 Android 编程时,如果出现与 相关的“找不到符号”错误,请注意,符号是由文件定义的。检查您的文件是否正确且位于正确的位置,以及是否已生成/编译相应的类文件。请注意,Java 符号区分大小写,因此相应的 XML ID 也区分大小写。RRcontext.xmlcontext.xmlR

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

  7. 隐藏系统类:我见过编译器抱怨这是一个未知符号的情况,如下所示substring

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

    事实证明,程序员已经创建了自己的版本,并且他的类版本没有定义方法。我见过人们在 和其他类中这样做。StringsubstringSystemScanner

    课:不要使用与公共库类相同的名称定义自己的类!

    该问题也可以通过使用完全限定的名称来解决。例如,在上面的示例中,程序员可以编写:

    java.lang.String s = ...
    java.lang.String s1 = s.substring(1);
    
  8. 同形异体:如果对源文件使用 UTF-8 编码,则标识符可能看起来相同,但实际上不同,因为它们包含同形异形。有关详细信息,请参阅此页面

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


1 - 如果确实在运行时异常或错误消息中看到此情况,则表示您已将 IDE 配置为运行包含编译错误的代码,或者应用程序正在生成和编译代码。在运行时。
2 - 土木工程的三个基本原则:水不会上坡,木板的侧面更坚固,你不能推绳子


答案 2

如果您忘记了:new

String s = String();

String s = new String();

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


推荐