“找不到符号”或“无法解析符号”错误是啥意思?
Posted
技术标签:
【中文标题】“找不到符号”或“无法解析符号”错误是啥意思?【英文标题】:What does a "Cannot find symbol" or "Cannot resolve symbol" error mean?“找不到符号”或“无法解析符号”错误是什么意思? 【发布时间】:2022-01-15 22:04:20 【问题描述】:请解释以下关于“找不到符号”、“无法解析符号”或“找不到符号”错误(在 Java 中):
它们是什么意思? 哪些因素会导致它们? 程序员如何修复它们?此问题旨在提供有关 Java 中这些常见编译错误的全面问答。
【问题讨论】:
【参考方案1】:0。这两个错误有什么区别吗?
不是真的。 “找不到符号”、“无法解析符号”和“找不到符号”都是同一个意思。不同的 Java 编译器使用不同的术语。
1。 “找不到符号”错误是什么意思?
首先,这是一个编译错误1。这意味着要么你的Java源代码有问题,或者你编译它的方式有问题。
您的 Java 源代码包含以下内容:
关键字:如class
、while
等。
文字:如true
、false
、42
、'X'
和"Hi mum!"
。
运算符和其他非字母数字标记:如+
、=
、
等。
标识符:如Reader
、i
、toString
、processEquibalancedElephants
等。
注释和空格。
“找不到符号”错误与标识符有关。编译代码时,编译器需要弄清楚代码中每个标识符的含义。
“找不到符号”错误意味着编译器无法执行此操作。您的代码似乎引用了编译器无法理解的内容。
2。什么会导致“找不到符号”错误?
作为第一个命令,只有一个原因。编译器查看了所有应该定义标识符 的地方,但找不到定义。这可能是由多种原因造成的。常见的有以下几种:
对于一般标识符:
也许你拼错了名字;即StringBiulder
而不是StringBuilder
。 Java 不能也不会尝试弥补拼写错误或输入错误。
也许你弄错了;即stringBuilder
而不是StringBuilder
。所有 Java 标识符都区分大小写。
也许你不恰当地使用了下划线;即mystring
和my_string
是不同的。 (如果你坚持 Java 风格的规则,你将在很大程度上避免这个错误......)
也许您正在尝试使用被声明为“其他地方”的东西;即在与您隐式告诉编译器查看的不同上下文中。 (不同的类?不同的范围?不同的包?不同的代码库?)
对于应该引用变量的标识符:
可能您忘记声明变量了。 也许变量声明在您尝试使用它时超出了范围。 (见下面的例子)对于应该是方法或字段名称的标识符:
也许您正在尝试引用未在父/祖先类或接口中声明的继承方法或字段。
也许您正在尝试引用您正在使用的类型中不存在(即尚未声明)的方法或字段;例如"rope".push()
2.
也许您正试图将方法用作字段,反之亦然;例如"rope".length
或 someArray.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);
如果您从命令行编译,编译器可能找不到符号还有另一个原因。您可能只是忘记了编译或重新编译其他一些类。例如,如果您有 Foo
和 Bar
类,其中 Foo
使用 Bar
。如果您从未编译过Bar
而运行javac Foo.java
,您很容易发现编译器找不到符号Bar
。简单的答案是将Foo
和Bar
一起编译;例如javac Foo.java Bar.java
或 javac *.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 < 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 等。在这种情况下,程序员最终可能会追着尾巴寻找一个虚幻的错误,实际上是由于没有正确重新编译代码等等......
早期构建问题:早期构建可能以某种方式失败,导致 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
方法。我见过有人用System
、Scanner
和其他类来做到这一点。
教训:不要定义自己的类与公共库类同名!
该问题也可以通过使用完全限定名称来解决。例如,在上面的例子中,程序员可以这样写:
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 可能会将其他错误“解释”到此类别中。例如println
in System.out.println
如果放置在标准编译器下的类级别会给我们 <identifier> 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);
这是无效的代码。因为名为@987654323@ 的变量在它们各自的范围之外都不可见——在这种情况下,这将是括号。
您可能会说:“但是一个名为 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 中一样。事实上,大多数“块结构”语言都是如此。 对于在每个分支上分配不同值的代码,更好的解决方案是使用blankfinal
变量声明。【参考方案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 -> 'Invalidate Caches/Restart'
或
被引用的类在另一个项目中,并且该依赖项未添加到我项目的 Gradle 构建文件中。所以我添加了依赖使用
compile project(':anotherProject')
它奏效了。 HTH!
【讨论】:
【参考方案11】:您使用 maven compile 编译了代码,然后使用 maven test 运行它工作正常。现在,如果您更改了代码中的某些内容,然后在不编译的情况下运行它,您将收到此错误。
解决方案:再次编译它,然后运行测试。对我来说,它是这样工作的。
【讨论】:
这个解释没有意义。 “找不到符号”错误是编译错误。它不会在 >>running> 编译 另外,我很困惑你设法编译测试而不编译被测代码。除非他们出于某种原因在单独的项目中。如果您运行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】:我这样解决了这个错误...android的疯狂。我将包名称作为适配器,我将名称重构为适配器,使用“a”而不是“A”并解决了错误。
【讨论】:
这不是 Android 特有的,也不是疯狂。 Java 标识符区分大小写。并且类名/包名的大小写要与对应的源文件、目录和.class文件的大小写一致。如果你搞砸了,那么工具链很可能找不到相关文件。 感谢 Stephen C 的澄清以上是关于“找不到符号”或“无法解析符号”错误是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章