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

Posted

技术标签:

【中文标题】“找不到符号”或“无法解析符号”错误是啥意思?【英文标题】:What does a "Cannot find symbol" or "Cannot resolve symbol" error mean?“找不到符号”或“无法解析符号”错误是什么意思? 【发布时间】:2021-08-26 11:21:18 【问题描述】:

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

它们是什么意思? 哪些因素会导致它们? 程序员如何修复它们?

此问题旨在提供有关 Java 中这些常见编译错误的全面问答。

【问题讨论】:

【参考方案1】:

0。这两个错误有什么区别吗?

不是真的。 “找不到符号”、“无法解析符号”和“找不到符号”都是同一个意思。不同的 Java 编译器使用不同的术语。

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

首先,这是一个编译错误1。这意味着要么你的Java源代码有问题,或者你编译它的方式有问题。

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

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

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

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

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

作为第一个命令,只有一个原因。编译器查看了所有应该定义标识符 的地方,但找不到定义。这可能是由多种原因造成的。常见的有以下几种:

对于一般标识符:

也许你拼错了名字;即StringBiulder 而不是StringBuilder。 Java 不能也不会尝试弥补拼写错误或输入错误。 也许你弄错了;即stringBuilder 而不是StringBuilder。所有 Java 标识符都区分大小写。 也许你不恰当地使用了下划线;即mystringmy_string 是不同的。 (如果你坚持 Java 风格的规则,你将在很大程度上避免这个错误......) 也许您正在尝试使用被声明为“其他地方”的东西;即在与您隐式告诉编译器查看的不同上下文中。 (不同的类?不同的范围?不同的包?不同的代码库?)

对于应该引用变量的标识符:

可能您忘记声明变量了。 也许变量声明在您尝试使用它时超出了范围。 (见下面的例子)

对于应该是方法或字段名称的标识符:

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

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

也许您正试图将方法用作字段,反之亦然;例如"rope".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 完成或自动更正,可能建议使用 java.awt.List 而不是 java.util.List。 可能您正在使用(编译)错误版本的 API。 可能您忘记将对象转换为适当的子类。 也许您已将变量的类型声明为您要查找的成员的超类型。

问题通常是上述问题的组合。例如,也许您“明星”导入了java.io.*,然后尝试使用Files 类......它位于java.nio 而不是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()) 
    ...

这将在if 语句中为i 提供“找不到符号”错误。虽然我们之前声明了i,但该声明仅for 语句及其主体的范围内if 语句中对i 的引用看不到 i 的声明。它超出范围

(此处适当的更正可能是将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 循环的主体,因此for 语句中i 的先前声明在块中超出范围


这是另一个由拼写错误导致的“找不到符号”错误示例。

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

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

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

int res = tmp * (a + b);

如果您从命令行编译,编译器可能找不到符号还有另一个原因。您可能只是忘记了编译或重新编译其他一些类。例如,如果您有 FooBar 类,其中 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 说“找不到符号”。有很多方法可以“解决”这个问题:

我可以将内部 for 更改为 for (int j = 1; j &lt; 10; j++) - 可能是正确的。 我可以为j 添加声明内部for 循环或外部for 循环 - 可能是正确的。 我可以在内部 for 循环中将 j 更改为 i - 可能是错误的! 等等。

关键是您需要了解您的代码试图做什么才能找到正确的修复方法。

4。原因不明

这里有几个“找不到符号”看似莫名其妙的情况......直到你仔细观察。

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

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

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

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

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

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

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

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

    这可能是一个 IDE 错误。例如,@Joel Costigliola 描述了 Eclipse 没有正确处理 Maven“测试”树的场景:see this answer。 (显然那个特定的错误很久以前就被修复了。)

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

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

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

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

    事实证明,程序员创建了自己的String 版本,而他的类版本没有定义substring 方法。我见过有人用SystemScanner 和其他类来做到这一点。

    教训:不要定义自己的类与公共库类同名!

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

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

    Homoglyphs:如果您对源文件使用 UTF-8 编码,则可能会有看起来相同但实际上不同的标识符,因为它们包含同形文字。请参阅this page 了解更多信息。

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


1 - 如果您确实在运行时异常或错误消息中看到这一点,那么您可能已将 IDE 配置为运行出现编译错误的代码,或者您的应用程序正在生成并在运行时编译代码。 2 - 土木工程的三个基本原则:水不会上坡,木板的侧面更坚固,你不能推动绳索

【讨论】:

我遇到了另一种情况,当 eclipse 没有看到问题时发生了这个编译错误:两个类分别在另一个类中定义了依赖项。在我的例子中,我有一个枚举,实现了一个接口,定义在一个我已经愚蠢地使用枚举的类中。 有点类似于上面的评论,当我从 Eclipse 编译和运行我的程序时,它没有问题。从控制台编译它会引发一堆“找不到符号”错误,这些错误通常与导入中的最后一个元素有关。我不知道是什么原因造成的,因为代码中没有任何问题。 另一个问题是 IDE 可能会将其他错误“解释”到此类别中。例如,System.out.println 中的 println 如果放在标准编译器下的类级别会得到 &lt;identifier&gt; expected (demo) 但在 IntelliJ 中我们会看到 Cannot resolve symbol 'println' (demo)。 哇。我称之为编译器错误。 (似乎 Intellij 采用了一些在语法上无效的东西(需要声明的语句),然后尝试解析符号。但是编译器已经完全搞砸了,它无法解析一个应该解析的符号......并且如果语句在正确的上下文中将解析。这会导致误导性的编译错误消息。)【参考方案2】:

如果您忘记了new,您也会收到此错误:

String s = String();

String s = new String();

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

【讨论】:

在扫描我的代码一个小时后,我发现了这个答案 - 感谢上帝!【参考方案3】:

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

我已经多次看到这类问题了,也许再举一个例子来说明什么是非法的,即使它可能感觉没问题。

考虑这段代码:

if(somethingIsTrue()) 
  String message = "Everything is fine";
 else 
  String message = "We have an error";

System.out.println(message);

这是无效的代码。因为名为@9​​87654323@ 的变量在它们各自的范围之外都不可见——在这种情况下,这将是括号

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

但你错了。

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

如果你认为你做了一件好事,那就特别糟糕了。我在“优化”这样的代码后看到了这种错误:

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

“哦,有重复的代码,让我们把那条公共线拉出来吧” -> 就在那里。

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

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

【讨论】:

"Java 没有 free() 或 delete 运算符,因此它必须依靠跟踪变量范围来找出何时不再使用变量(连同对这些变量的引用) ." - 虽然是真的,但这不相关。 C 和 C++ 分别具有 free / delete 运算符,但是与您的示例等效的 C / C++ 代码将是非法的。 C 和 C++ 块限制变量的范围,就像在 Java 中一样。事实上,大多数“块结构”语言都是如此。 对于在每个分支上分配不同值的代码,更好的解决方案是使用blank final 变量声明。【参考方案4】:

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

    src/test/java 中定义一个类A。 在src/main/java 中定义另一个使用类A 的类B

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

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

解决方案:

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

【讨论】:

这个有什么解决办法? 无论你在 src/main/java 中使用什么,都需要在 src/main/java 或任何编译/运行时依赖项(不是测试依赖项)中定义。【参考方案5】:

已解决

使用 IntelliJ

选择Build->Rebuild Project会解决的

【讨论】:

这在很大程度上取决于而且通常不会。 这对我有用。我无法弄清楚,因为包/目录都是正确的。似乎需要重新构建以合并更改。【参考方案6】:

“找不到”意味着编译器找不到合适的变量、方法、类等……如果你得到那个错误消息,首先你要找到得到错误消息的代码行……并且那么你就可以在使用之前找到哪个变量,方法或类没有定义。确认初始化该变量,方法或类可以用于以后的需求...考虑以下示例。

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

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);
      

现在看看新的输出...

Ok 成功解决了那个错误..同时,如果你能得到“找不到方法”或“找不到类”的东西,首先,定义一个类或方法,然后使用它..

【讨论】:

【参考方案7】:

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

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

【讨论】:

【参考方案8】:

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

在 Eclipse 中,如果 Java 映射到 Java 版本 11,并且在 pom.xml 中它被映射到 Java 版本 8。通过 Eclipse IDE 中的以下步骤将 Eclipse 支持更新到 Java 11 帮助 -> 安装新软件 ->

Work With

处粘贴以下链接 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 build steps

【讨论】:

【参考方案9】:

我也遇到了这个错误。 (为此我用谷歌搜索并被定向到此页面)

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

error: cannot find symbol

解决方案:我解决了这个问题,首先构建定义方法的项目,然后构建调用方法的项目。

【讨论】:

是的,例如,如果您决定将某些可重用函数从当前包移动到通用 utils 包,但随后您忘记在从当前包调用该函数之前编译通用包,就会发生这种情况包。【参考方案10】:

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

    如果您使用的是 IntelliJ

    File -&gt; 'Invalidate Caches/Restart'

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

    compile project(':anotherProject')

它奏效了。 HTH!

【讨论】:

【参考方案11】:

您使用 maven compile 编译了代码,然后使用 maven test 运行它工作正常。现在,如果您更改了代码中的某些内容,然后在不编译的情况下运行它,您将收到此错误。

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

【讨论】:

这个解释没有意义。 “找不到符号”错误是编译错误。它不会在 >>running>compiling 另外,我很困惑你设法编译测试而不编译被测代码。除非他们出于某种原因在单独的项目中。如果您运行mvn test,则应该重新编译项目中的所有内容......在运行测试之前。如果你运行mvn surefile:test,那不应该重新编译任何东西。【参考方案12】:

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

    context.xml 文件从src/java/package 移动到resource 目录(IntelliJ IDE) 清理target目录。

【讨论】:

在不关心引用的情况下移动文件可能会导致此错误。我已经遇到了这个。只需在 Git 上重置并再次小心移动,错误就解决了。【参考方案13】:

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

另一个原因是 java 版本不支持的方法说 jdk7 vs 8。 检查你的 %JAVA_HOME%

【讨论】:

这和其他答案说的一样。【参考方案14】:

我们在设置为 Gradle 多项目构建的 Java 项目中遇到错误。原来,其中一个子项目缺少Gradle Java Library plugin。 这会阻止子项目的类文件对构建中的其他项目可见。

通过以下方式将Java库插件添加到子项目的build.gradle后,错误消失了:

plugins 
    ...
    id 'java-library'

【讨论】:

【参考方案15】:

回复:4.4:Stephen C 出色回答中的早期构建问题

我在开发 osgi 应用程序时遇到了这种情况。 我有一个 java 项目 A,它是 B 的依赖项。 构建B时出现错误:

Compilation failure: org.company.projectA.bar.xyz does not exist

但是在eclipse中,完全没有编译问题。

调查 当我查看A.jar 时,有org.company.projectA.foo.abc 的课程,但org.company.projectA.bar.xyz 没有课程。

缺少类的原因,是在A/pom.xml中,是导出相关包的入口。

<plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    ...
    <configuration>
        <instructions>
            ....
            <Export-Package>org.company.projectA.foo.*</Export-Package>
        </instructions>
    </configuration>
</plugin>

解决方案 像这样添加缺少的包:

<Export-Package>org.company.projectA.foo.*,org.company.projectA.bar.*</Export-Package>

然后重建一切。

现在A.jar 包含所有预期的类,并且所有内容都可以编译。

【讨论】:

【参考方案16】:

它们是什么意思?

这三个语句的含义相同:“找不到符号”、“无法解析符号”和“找不到符号”。

现在,错误的意思是编译器无法理解定义符号的引用。或者只是编译器无法做到这一点。

原因及解决方法

如果您在其他地方的构建中遇到此错误,而您的 IDE 显示一切正常,请检查您是否在两个地方使用相同的 Java 版本。 如果您在其他地方的构建中遇到此错误,并且您的 IDE 说一切正常,请检查是否在两个地方使用了相同的 Java 版本。

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

【讨论】:

【参考方案17】:

我在编译我的项目时遇到了同样的问题,我检查了我的 java 编译器版本,它曾经在 java 1.8 上工作,但不小心设置为 java 17,我将它改回版本 1.8,我的问题得到了解决。

【讨论】:

【参考方案18】:

我这样解决了这个错误...android的疯狂。我将包名称作为适配器,我将名称重构为适配器,使用“a”而不是“A”并解决了错误。

【讨论】:

这不是 Android 特有的,也不是疯狂。 Java 标识符区分大小写。并且类名/包名的大小写要与对应的源文件、目录和.class文件的大小写一致。如果你搞砸了,那么工具链很可能找不到相关文件。 感谢 Stephen C 的澄清

以上是关于“找不到符号”或“无法解析符号”错误是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章

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

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

java中提示找不到符号

java 中 “找不到符号”的错误

java 枚举 找不到符号

java package找不到符号