请解释以下有关“找不到符号”、“无法解析符号”或“找不到符号”错误(Java 中)的信息:
这个问题旨在对 Java 中的这些常见编译错误进行全面的问答。
P粉2037924682023-10-10 12:40:19
如果您忘记了new
,您也会收到此错误:
String s = String();
对比
String s = new String();
因为不带 new
关键字的调用将尝试查找不带参数的名为 String
的(本地)方法 - 并且该方法签名可能未定义。 p>
P粉9464374742023-10-10 11:07:06
不是真的。 “找不到符号”、“无法解析符号”和“找不到符号”都意味着同一件事。 (不同的Java编译器是由不同的人编写的,不同的人用不同的措辞来表达同样的事情。)
首先,这是一个编译错误1。这意味着您的 Java 源代码中存在问题,或者您的编译方式存在问题。
您的 Java 源代码包含以下内容:
class
、while
等。true
、false
、42
、'X'
和 “嗨妈妈!”
。+
、=
、{
等。Reader
、i
、toString
、processEquibalancedElephants
等。“找不到符号”错误与标识符有关。编译代码时,编译器需要计算出代码中每个标识符的含义。
“找不到符号”错误意味着编译器无法执行此操作。您的代码似乎引用了编译器无法理解的内容。
作为第一顺序,只有一个原因。编译器查看了应该定义标识符的所有位置,但找不到定义。这可能是由多种原因造成的。常见的有以下几种:
对于一般标识符:
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()'
也许您正在尝试导入或以其他方式使用已在默认包中声明的类;即没有 package
语句的类所在的位置。
提示:了解包。您应该只对由一个类组成的简单应用程序使用默认包...或者至少由一个 Java 源文件组成。
对于类型或实例似乎不具有您期望它具有的成员(例如方法或字段)的情况:
java.awt.List
而不是 java.util.List
。问题通常是上述问题的组合。例如,也许您“明星”导入了 java.io.*
,然后尝试使用 Files
类...它位于 java.nio代码>而不是
java.io
。或者,也许您打算编写 File
...,它是 java.io
中的一个类。
以下示例说明了不正确的变量作用域如何导致“找不到符号”错误:
Liststrings = ... 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
循环的主体,因此之前在 i
中的声明code>for 语句超出块中的范围。
这是由拼写错误引起的“找不到符号”错误的另一个示例。
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 等。
还有一些其他更模糊的原因......我将在下面讨论。
一般来说,您首先要找出导致编译错误的原因。
然后你思考你的代码应该说什么。最后,您确定需要对源代码进行哪些更正才能完成您想要的操作。
请注意,并非每个“更正”都是正确的。考虑一下:
for (int i = 1; i < 10; i++) { for (j = 1; j < 10; j++) { ... } }
假设编译器对 j
提示“找不到符号”。我可以通过很多方法“修复”这个问题:
for
更改为 for (int j = 1; j < 10; j++)< 10; j++)
- 可能是正确的。for
循环或外部 for
循环之前添加一个 for j
声明 -可能是正确的。for
循环中将 j
更改为 i
- 可能是错误的!重点是,您需要了解您的代码正在尝试执行的操作,以便找到正确的修复方法。
在以下几个案例中,“找不到符号”似乎令人费解……直到您仔细观察。
不正确的依赖项:如果您使用的是管理构建路径和项目依赖项的 IDE 或构建工具,则您可能在依赖项方面犯了错误;例如遗漏了依赖项,或选择了错误的版本。如果您使用构建工具(Ant、Maven、Gradle 等),请检查项目的构建文件。如果您使用的是 IDE,请检查项目的构建路径配置。
找不到符号“var”:您可能正在尝试使用较旧的版本来编译使用局部变量类型推断(即 var
声明)的源代码编译器或更旧的 --source
级别。 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 s = ... String s1 = s.substring(1);
事实证明,程序员创建了他们自己的 String
版本,并且他的类版本没有定义 substring
方法。我见过人们使用 System
、Scanner
和其他类来执行此操作。
教训:不要定义与公共库类同名的自己的类!
该问题也可以通过使用完全限定名称来解决。例如,在上面的示例中,程序员可以编写:
java.lang.String s = ... java.lang.String s1 = s.substring(1);
同形文字:如果您对源文件使用 UTF-8 编码,则可能会出现看起来相同但实际上不同的标识符因为它们包含同形文字。请参阅此页面了解更多信息。
您可以通过限制自己使用 ASCII 或 Latin-1 作为源文件编码,并使用 Java \uxxxx
转义其他字符来避免这种情况。
1 - 如果您确实在运行时异常或错误消息中看到此情况,则说明您已将 IDE 配置为运行带有编译错误的代码,或者您的应用程序正在生成并在运行时编译代码。
2 - 土木工程的三个基本原理:水不往高处流、木板越面越坚固、你推不动绳子。