请解释以下有关“找不到符号”、“无法解析符号”或“未找到符号”错误(在 Java 中):
- 他们的意思是什么?
- 什么事情会导致他们?
- 程序员如何修复它们?
这个问题旨在为有关 Java 中这些常见编译错误的全面问答提供种子。
原文由 Stephen C 发布,翻译遵循 CC BY-SA 4.0 许可协议
请解释以下有关“找不到符号”、“无法解析符号”或“未找到符号”错误(在 Java 中):
这个问题旨在为有关 Java 中这些常见编译错误的全面问答提供种子。
原文由 Stephen C 发布,翻译遵循 CC BY-SA 4.0 许可协议
如果您忘记了 new
,您也会收到此错误:
String s = String();
相对
String s = new String();
因为没有 new
关键字的调用将尝试查找名为 String
的(本地)方法,没有参数 - 并且该方法签名可能未定义。
原文由 thinkterry 发布,翻译遵循 CC BY-SA 4.0 许可协议
4 回答1.2k 阅读✓ 已解决
4 回答1.2k 阅读✓ 已解决
1 回答2.5k 阅读✓ 已解决
2 回答704 阅读✓ 已解决
2 回答1.7k 阅读
2 回答1.6k 阅读
2 回答1.3k 阅读
0. 这些错误有什么区别吗?
并不真地。 “找不到符号”、“无法解析符号”和“找不到符号”都是同一个意思。 (不同的Java编译器是由不同的人编写的,不同的人用不同的措辞来表达同样的事情。)
1. “找不到符号”错误是什么意思?
首先,这是一个 编译错误 1 。这意味着 要么 你的 Java 源代码有问题, 要么 你编译它的方式有问题。
您的 Java 源代码包含以下内容:
class
、while
等。true
,false
,42
,'X'
and"Hi mum!"
.+
、=
、{
等等。Reader
,i
toString
processEquibalancedElephants
“找不到符号”错误与标识符有关。编译代码时,编译器需要弄清楚代码中每个标识符的含义。
“找不到符号”错误意味着编译器无法执行此操作。您的代码似乎指的是编译器不理解的东西。
2. 什么会导致“找不到符号”错误?
作为第一顺序,只有一个原因。编译器查看了所有 应该 定义标识符的地方,但找不到定义。这可能是由多种原因造成的。常见的有以下几种:
对于一般标识符:
StringBiulder
而不是StringBuilder
。 Java 不能也不会尝试弥补拼写错误或输入错误。stringBuilder
而不是StringBuilder
。所有 Java 标识符都区分大小写。mystring
和my_string
是不同的。 (如果你坚持 Java 风格的规则,你将在很大程度上避免这个错误……)对于应该引用变量的标识符:
对于应该是方法或字段名称的标识符:
也许您正在尝试引用未在父/祖先类或接口中声明的继承方法或字段。
也许您正试图引用您正在使用的类型中不存在(即尚未声明)的方法或字段;例如
"rope".push()
2 。也许您正在尝试将方法用作字段,反之亦然;例如
"rope".length
或someArray.length()
。也许您错误地对数组而不是数组元素进行了操作;例如
对于应该是类名的标识符:
也许您忘记了导入该类。
也许您使用了“星号”导入,但该类未在您导入的任何包中定义。
也许你忘记了
new
如下:对于类型或实例似乎没有您期望的成员(例如方法或字段)的情况:
java.awt.List
而不是java.util.List
。问题通常是上述问题的组合。 For example, maybe you “star” imported
java.io.*
and then tried to use theFiles
class … which is injava.nio
notjava.io
。或者,也许您打算写File
… 这 是java.io
中的一个类。以下是不正确的变量范围如何导致“找不到符号”错误的示例:
这将在
if
语句中为i
给出“找不到符号”错误。虽然我们之前声明了i
,但该声明仅 在for
语句及其主体的范围内。在if
语句中对i
的引用 看不到i
的声明。它 _超出了范围_。(此处适当的更正可能是将
if
语句移到循环内,或者在循环开始之前声明i
。)这是一个导致困惑的示例,其中一个错字导致看似莫名其妙的“找不到符号”错误:
这将在
println
调用中给您一个编译错误,说i
找不到。但是(我听到你说)我确实宣布了!问题是在 --- 之前的偷偷摸摸的分号(
;
{
。 Java 语言语法将该上下文中的分号定义为 _空语句_。然后,空语句成为for
循环的主体。所以该代码实际上意味着:{ ... }
块不是for
循环的主体,因此i
在for
的语句中 的 前一个声明块中的 _范围_。这是由拼写错误引起的“找不到符号”错误的另一个示例。
尽管前面有声明,但
tmp
tmp(...)
是错误的。编译器将寻找一种名为tmp
的方法,但找不到。先前声明的tmp
位于变量的命名空间中,而不是方法的命名空间中。在我遇到的示例中,程序员实际上遗漏了一个运算符。他想写的是这样的:
如果您从命令行编译,编译器可能找不到符号还有另一个原因。您可能只是忘记了编译或重新编译其他一些类。例如,如果您有类
Foo
和Bar
其中Foo
使用Bar
。如果您从未编译过Bar
并运行javac Foo.java
,您很容易发现编译器找不到符号Bar
。简单的答案是将Foo
和Bar
一起编译;例如javac Foo.java Bar.java
或javac *.java
。或者最好还是使用 Java 构建工具;例如 Ant、Maven、Gradle 等。还有一些其他更模糊的原因……我将在下面处理。
3. 如何修复这些错误?
一般来说,您首先要找出 导致 编译错误的原因。
然后你 想想 你的代码应该说什么。最后,您确定需要对源代码进行哪些更正以执行您想要的操作。
请注意,并非每个“更正”都是正确的。考虑一下:
假设编译器对
j
说“找不到符号”。我有很多方法可以“解决”这个问题:for
更改为for (int j = 1; j < 10; j++)
- 可能是正确的。for
循环或外部for
循环 之前 添加j
的声明 - 可能是正确的。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“测试”树的场景: 见这个答案。 (显然,那个特定的错误很久以前就被修复了。)
Android 问题:当您为 Android 编程时,出现与
R
相关的“找不到符号”错误,请注意R
符号由context.xml
定义---
文件。检查您的context.xml
文件是否正确且在正确的位置,以及相应的R
类文件是否已生成/编译。请注意,Java 符号区分大小写,因此相应的 XML id 也区分大小写。Android 上的其他符号错误可能是由于前面提到的原因;例如,缺少或不正确的依赖项、不正确的包名称、特定 API 版本中不存在的方法或字段、拼写/键入错误等等。
隐藏系统类:我见过编译器抱怨
substring
是一个未知符号的情况,如下所示事实证明,程序员已经创建了他们自己版本的
String
并且他的类版本没有定义substring
方法。我见过人们用System
,Scanner
和其他类来做这个。教训: 不要使用与公共库类相同的名称定义自己的类!
该问题也可以通过使用完全限定名称来解决。例如,在上面的示例中,程序员 可以 编写:
您可以通过将自己限制为 ASCII 或 Latin-1 作为源文件编码并使用 Java
\uxxxx
对其他字符进行转义来避免这种情况。1 - 如果您 确实 在运行时异常或错误消息中看到了这一点,那么您已经将 IDE 配置为运行带有编译错误的代码,或者您的应用程序正在生成和编译代码……在运行时。
2 - 土木工程的三个基本原则:水不会上坡,木板的侧面更坚固, _你不能推动绳索_。