“找不到符号”;或“不能解析符号”;错误的意思吗?

请解释“不能找到符号”、“不能解析符号”的含义。或“符号未找到”;错误(Java):

  • 它们是什么意思?
  • 什么东西会引起它们?
  • 程序员如何着手修复它们?

这个问题的目的是提供一个关于Java中常见编译错误的全面问答。

1457020 次浏览

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

不是真的。“不能找到符号”、“不能解析符号”;和“符号未找到”;都是同一个意思。(不同的Java编译器是由不同的人编写的,不同的人使用不同的措辞来表达相同的事情。)

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

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

您的Java源代码由以下内容组成:

  • 关键字:像classwhile,等等。
  • 字面量:像truefalse42'X'"Hi mum!"
  • 操作符和其他非字母数字标记:如+={,等等。
  • 标识符:比如ReaderitoStringprocessEquibalancedElephants,等等。
  • 注释和空格。

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

A“找不到符号”;错误意味着编译器不能这样做。你的代码似乎引用了编译器不理解的东西。

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)'
      
  • 对于应该是类名的标识符:

    • 也许您忘记导入类。

    • 也许你用了"star"导入,但是该类没有在您导入的任何包中定义。

    • 也许你忘记了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.javaBar0。或者最好还是使用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 < 10; j++) -可能是正确的。
  • 我可以为j 之前添加一个声明,即内部的for循环,或外部的for循环——可能是正确的。
  • 我可以在内部的for循环中将j更改为i -可能是错误的!
  • 等等。

关键是你需要来理解你的代码试图做什么,以便找到正确的修复。

4. 模糊的原因

以下是“找不到符号”的几种情况:似乎是无法解释的…直到你仔细看。

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

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

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

    另一个例子是当你使用(Java 9+) java SomeClass.java来编译和运行一个类。如果这个类依赖于另一个你没有编译(或重新编译)的类,你很容易得到“不能解析符号”;关于第二类的错误。其他源文件不会自动编译。java命令的新“编译和运行”;模式不是为运行具有多个源代码文件的程序而设计的。

  4. 早期的构建问题:有可能早期构建失败,导致JAR文件中缺少类。如果您正在使用构建工具,通常会注意到这种失败。然而,如果你从别人那里获得JAR文件,你就依赖于他们的正确构建,并注意到错误。如果你怀疑这一点,使用tar -tvf列出怀疑JAR文件的内容。

  5. IDE的问题:人们报告了IDE被混淆的情况,IDE中的编译器无法找到存在的类…或者相反的情况。

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

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

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

  6. 安卓系统问题:当你为Android编程时,你有"不能找到符号"如果存在与R相关的错误,请注意R符号是由context.xml文件定义的。检查你的context.xml文件是否正确并且在正确的位置,并且相应的R类文件已经生成/编译。注意,Java符号是区分大小写的,因此对应的XML id也是区分大小写的。

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

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

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

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

    不要用和普通库类相同的名字定义你自己的类!

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

    java.lang.String s = ...
    java.lang.String s1 = s.substring(1);
    
  8. 如果你对源文件使用UTF-8编码,可能会有相同的标识符,但实际上是不同的,因为它们包含同构符号。更多信息见这个页面

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


1 -如果,你在运行时异常或错误消息中看到这个,那么要么你已经配置了你的IDE来运行带有编译错误的代码,要么你的应用程序正在生成和编译代码。在运行时。< br > 2 -土木工程的三个基本原则:水不往山上流,木板在其一侧更坚固,你不能推绳子.

. 3

如果你忘记new,你也会得到这个错误:

String s = String();

String s = new String();

因为不带new关键字的调用将尝试寻找一个不带参数的名为String的(本地)方法——而且该方法签名可能没有定义。

再举一个"变量超出范围"的例子

这类问题我已经见过几次了,也许是另一个违法的例子,即使它可能感觉 okay。

考虑下面的代码:

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

这是无效代码。因为命名为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);

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

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

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

  1. src/test/java中定义一个类A
  2. src/main/java中定义另一个类B,它使用类A

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

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

解决方案:

  1. 不要那样定义你的依赖关系;也就是说,不要犯这样的错误。
  2. 定期使用Maven构建代码库,以便尽早发现这个错误。实现这一点的一种方法是使用CI服务器。

我也得到了这个错误。(我在谷歌上搜索了一下,然后转到了这个页面)

我从另一个项目B中定义的类中调用项目a的类中定义的静态方法。 我得到以下错误:

error: cannot find symbol

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

对于提示,仔细查看抛出错误的类名name和行号,例如: 编译失败 [ERROR] \applications\xxxxx.java:[44,30] ERROR:不能找到符号

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

“找不到”的意思是,编译器找不到合适的变量,方法,类等…如果你得到了错误提示,首先你要找到得到错误提示的代码行,然后你就可以在使用它之前找到哪个变量、方法或类没有定义。确认初始化该变量后,方法或类可以用于以后的需要…考虑下面的例子。

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

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

现在看看结果。

enter image description here

该错误说,“变量名找不到”..为name变量定义并初始化值可以消除该错误。

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


String name="smith";


System.out.print(name);
}
}

现在看看新的输出……

enter image description here

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

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

  1. 如果您正在使用IntelliJ

    File -> 'Invalidate Caches/Restart' < / p >

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

    compile project(':anotherProject') < / p >

这招奏效了。HTH !

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

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

将下面的链接http://download.eclipse.org/eclipse/updates/4.9-P-builds粘贴到< em >与< / em >

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

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

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

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

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

您使用maven compile编译代码,然后使用maven test运行它,结果很好。现在,如果你在代码中改变了一些东西,然后在没有编译的情况下运行它,你会得到这个错误。

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

在我的情况下,我必须执行以下操作:

  1. context.xml文件从src/java/package移动到resource目录 李IDE) < / >
  2. 清理target目录。

解决了

使用IntelliJ

选择构建->重建项目将解决它

我们在一个Java项目中得到了一个错误,这个错误被设置为一个Gradle多项目构建。结果发现其中一个子项目缺少Gradle Java库插件。 这阻止了子项目的类文件对构建中的其他项目可见

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

plugins {
...
id 'java-library'
}

enter image description here

我是这样解决这个错误的……疯狂的机器人。我把包的名称命名为适配器,然后用“&;a"而不是"A"解决了这个错误。

在Stephen C的精彩回答中回复:4.4:早期的构建问题

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

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

但是在eclipse中,根本不存在编译问题。

< p > 调查
当我在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>


< p > 解决方案

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

重建一切。

现在A.jar包含了所有期望的类,并且所有东西都编译了。

我在误差以下

java: cannot find symbol
symbol: class __

要解决这个问题

我尝试启用lambok,重新启动intellij等,但下面对我有用。

Intellij首选项->共享构建流程虚拟机选项,设置为

  -Djps.track.ap.dependencies=false

比跑

mvn clean install

Optional.isEmpty ()

我很高兴在我的IDE中使用!Optional.isEmpty(),它工作得很好,因为我正在用>= JDK11编译/运行我的项目。现在,当我在命令行上使用Gradle(在JDK8上运行)时,我在编译任务中得到了严重的错误。

为什么?

从文档中(注意最后一行):

boolean java.util.Optional.isEmpty()


If a value is not present, returns true, otherwise false.
Returns:true if a value is not present, otherwise false
Since:11