0. 这些错误之间有什么区别吗?
并不真地。 “找不到符号”、“无法解析符号”和“找不到符号”都意味着同一件事。 (不同的Java编译器是由不同的人编写的,不同的人用不同的措辞来表达同样的事情。)
1. “找不到符号”错误是什么意思?
Firstly, it is a compilation error1. It means that either there is a problem in your Java source code, or there is a problem in the way that you are compiling it.
您的 Java 源代码包含以下内容:
- 关键词:喜欢
class
, while
, 等等。
- 字面意思:像
true
, false
, 42
, 'X'
and "Hi mum!"
.
- 运算符和其他非字母数字标记:例如
+
, =
, {
, 等等。
- 标识符:像
Reader
, i
, toString
, processEquibalancedElephants
, 等等。
- 注释和空白。
“找不到符号”错误与标识符有关。编译代码时,编译器需要计算出代码中每个标识符的含义。
“找不到符号”错误意味着编译器无法执行此操作。您的代码似乎引用了编译器无法理解的内容。
2. 什么会导致“找不到符号”错误?
作为第一顺序,只有一个原因。编译器查看了标识符所在的所有位置should被定义,但找不到定义。这可能是由多种原因造成的。常见的有以下几种:
问题通常是上述问题的组合。例如,也许您“明星”导入java.io.*
然后尝试使用Files
类...是在java.nio
not java.io
。或者也许你想写File
... 哪个is一个班级在java.io
.
以下示例说明了不正确的变量作用域如何导致“找不到符号”错误:
List<String> strings = ...
for (int i = 0; i < strings.size(); i++) {
if (strings.get(i).equalsIgnoreCase("fnord")) {
break;
}
}
if (i < strings.size()) {
...
}
这将给出“找不到符号”错误i
in the if
陈述。虽然我们之前声明过i
,该声明只是in scope为了for
声明及其正文。参考i
in the if
陈述看不到该声明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);
}
The { ... }
块不是主体for
循环,因此之前的声明i
in the for
声明是超出范围在街区里。
这是由拼写错误引起的“找不到符号”错误的另一个示例。
int tmp = ...
int res = tmp(a + b);
尽管有先前的声明,tmp
in the tmp(...)
的表达是错误的。编译器会寻找一个名为的方法tmp
,并且找不到。之前宣布的tmp
位于变量的命名空间中,而不是方法的命名空间中。
在我遇到的例子中,程序员实际上遗漏了一个运算符。他本来想写的是这样的:
int res = tmp * (a + b);
如果从命令行编译,编译器可能找不到符号还有另一个原因。您可能只是忘记编译或重新编译其他一些类。例如,如果您有课程Foo
and Bar
where Foo
uses Bar
。如果你从未编译过Bar
你跑javac Foo.java
,你很容易发现编译器找不到这个符号Bar
。简单的答案是编译Foo
and Bar
一起;例如javac Foo.java Bar.java
or javac *.java
。或者最好还是使用 Java 构建工具;例如Ant、Maven、Gradle 等。
还有一些其他更模糊的原因......我将在下面讨论。
3. 如何修复这些错误?
一般来说,你首先要弄清楚什么caused编译错误。
- 查看文件中由编译错误消息指示的行。
- 确定错误消息所谈论的是哪个符号。
- 弄清楚why编译器说它找不到该符号;往上看!
然后你think关于你的代码应该说的内容。最后,您确定需要对源代码进行哪些修正才能完成您想要的操作。
请注意,并非每个“更正”都是正确的。考虑一下:
for (int i = 1; i < 10; i++) {
for (j = 1; j < 10; j++) {
...
}
}
假设编译器说“找不到符号”j
。我可以通过很多方法“修复”这个问题:
- 我可以改变内心
for
to for (int j = 1; j < 10; j++)
- 可能是正确的。
- 我可以添加一个声明
j
before内在的for
循环,或外层for
循环 - 可能是正确的。
- 我可以改变
j
to i
在内部for
循环 - 可能是错误的!
- 等等。
重点是你need了解您的代码正在尝试做什么,以便找到正确的修复方法。
4. 不明原因
在以下几个案例中,“找不到符号”似乎令人费解……直到您仔细观察。
-
不正确的依赖关系:如果您使用的是管理构建路径和项目依赖项的 IDE 或构建工具,则您可能在依赖项上犯了错误;例如遗漏了依赖项,或选择了错误的版本。如果您使用构建工具(Ant、Maven、Gradle 等),请检查项目的构建文件。如果您使用的是 IDE,请检查项目的构建路径配置。
-
找不到符号“var”:您可能正在尝试编译使用局部变量类型推断的源代码(即var
声明)与较旧的编译器或较旧的--source
等级。这var
在 Java 10 中引入。检查您的 JDK 版本和构建文件,以及(如果在 IDE 中发生这种情况)IDE 设置。
-
您没有编译/重新编译:有时,新的 Java 程序员不了解 Java 工具链是如何工作的,或者没有实现可重复的“构建过程”;例如使用 IDE、Ant、Maven、Gradle 等。在这种情况下,程序员最终可能会追着尾巴寻找一个虚幻的错误,即actually由于未正确重新编译代码等原因造成的。
另一个例子是当您使用 (Java 9+)java SomeClass.java
编译并运行一个类。如果该类依赖于您尚未编译(或重新编译)的另一个类,则您可能会收到涉及第二类的“无法解析符号”错误。其他源文件不会自动编译。这java
命令的新“编译并运行”模式不适用于运行具有多个源代码文件的程序。
-
早期构建问题:早期的构建可能会失败,导致 JAR 文件缺少类。如果您使用构建工具,通常会注意到此类失败。但是,如果您从其他人那里获取 JAR 文件,那么您就依赖于them正确构建并注意错误。如果您怀疑这一点,请使用tar -tvf
列出可疑 JAR 文件的内容。
-
IDE问题:人们报告了他们的 IDE 变得混乱并且 IDE 中的编译器找不到存在的类的情况......或者相反的情况。
-
如果 IDE 配置了错误的 JDK 版本,则可能会发生这种情况。
-
如果 IDE 的缓存与文件系统不同步,则可能会发生这种情况。有一些 IDE 特定的方法可以解决这个问题。
-
这可能是 IDE 错误。例如,@Joel Costigliola 描述了 Eclipse 无法正确处理 Maven“测试”树的场景:看到这个答案 https://stackoverflow.com/a/37207223/139985。 (显然这个特定的错误很久以前就被修复了。)
-
安卓问题:当您为 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
和其他课程。
Lesson:不要定义与公共库类同名的自己的类!
该问题也可以通过使用完全限定名称来解决。例如,在上面的例子中,程序员could已经写了:
java.lang.String s = ...
java.lang.String s1 = s.substring(1);
-
同形字:如果您对源文件使用 UTF-8 编码,则可能具有以下标识符:look相同,但实际上不同,因为它们包含同形文字。看这一页 http://en.wikipedia.org/wiki/Homoglyph了解更多信息。
您可以通过将自己限制为 ASCII 或 Latin-1 作为源文件编码并使用 Java 来避免这种情况\uxxxx
其他字符的转义。
1 - If, perchance, you do see this in a runtime exception or error message, then either you have configured your IDE to run code with compilation errors, or your application is generating and compiling code .. at runtime.
2 - The three basic principles of Civil Engineering: water doesn't flow uphill, a plank is stronger on its side, and you can't push on a rope.