请解释以下有关“找不到符号”、“无法解析符号”或“未找到符号”错误(在 Java 中):
- 他们的意思是什么?
- 什么事情会导致他们?
- 程序员如何修复它们?
这个问题旨在为有关 Java 中这些常见编译错误的全面问答提供种子。
请解释以下有关“找不到符号”、“无法解析符号”或“未找到符号”错误(在 Java 中):
这个问题旨在为有关 Java 中这些常见编译错误的全面问答提供种子。
并不真地。“找不到符号”、“无法解析符号”和“找不到符号”都是同一个意思。不同的 Java 编译器使用不同的措辞。
首先,这是一个编译错误1 。这意味着要么你的 Java 源代码有问题,要么你编译它的方式有问题。
您的 Java 源代码包含以下内容:
class
, while
, 等等。true
, false
, 42
, 'X'
and "Hi mum!"
.+
、=
、{
等。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()'
对于类型或实例似乎没有您期望的成员(例如方法或字段)的情况:
java.awt.List
而不是java.util.List
.问题通常是上述问题的组合。例如,也许你“星”导入java.io.*
然后尝试使用Files
类...在java.nio
not中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()) {
...
}
i
这将在if
语句中给出“找不到符号”错误。尽管我们之前声明i
了 ,但该声明仅在语句及其主体的范围内。声明中for
对的引用看不到i
的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);
}
该{ ... }
块不是for
循环的主体,因此语句中i
的先前声明超出了该块的范围。for
这是由拼写错误引起的“找不到符号”错误的另一个示例。
int tmp = ...
int res = tmp(a + b);
尽管前面有声明,但表达式tmp
中的 the是错误的。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++)
- 可能是正确的。j
之前添加一个声明- 可能是正确的。for
for
j
在内i
循环for
- 可能是错的!关键是您需要了解您的代码试图做什么才能找到正确的修复程序。
以下是一些“找不到符号”看似莫名其妙的情况......直到你仔细观察。
不正确的依赖关系:如果您使用管理构建路径和项目依赖关系的 IDE 或构建工具,您可能在依赖关系方面犯了错误;例如,遗漏了一个依赖项,或者选择了错误的版本。如果您使用的是构建工具(Ant、Maven、Gradle 等),请检查项目的构建文件。如果您使用的是 IDE,请检查项目的构建路径配置。
找不到符号 'var'var
:您可能正在尝试使用较旧的编译器或较旧--source
级别的编译器编译使用局部变量类型推断(即声明)的源代码。是在 Java 10 中引入的var
。检查您的 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);
Homoglyphs: 如果您对源文件使用 UTF-8 编码,则可能会有看起来相同但实际上不同的标识符,因为它们包含同形文字。请参阅此页面了解更多信息。
您可以通过将自己限制为 ASCII 或 Latin-1 作为源文件编码以及\uxxxx
对其他字符使用 Java 转义来避免这种情况。
1 - 如果您确实在运行时异常或错误消息中看到了这一点,那么您可能已将 IDE 配置为运行出现编译错误的代码,或者您的应用程序正在运行时生成和编译代码。
2 - 土木工程的三个基本原则:水不会上坡,木板的侧面更坚固,你不能推动绳索。
如果您忘记 a ,您也会收到此错误new
:
String s = String();
相对
String s = new String();
因为不带new
关键字的调用将尝试查找不带参数调用的(本地)方法String
- 并且该方法签名可能未定义。
“变量超出范围”的另一个示例
正如我已经多次看到这类问题的那样,也许再举一个例子来说明什么是非法的,即使它可能感觉还不错。
考虑这段代码:
if(somethingIsTrue()) {
String message = "Everything is fine";
} else {
String message = "We have an error";
}
System.out.println(message);
那是无效代码。因为命名的变量message
在它们各自的范围之外都不可见 -{}
在这种情况下,这将是周围的括号。
你可能会说:“但是一个名为 message 的变量是以任何一种方式定义的——所以 message是在”之后定义的if
。
但你错了。
Java 没有free()
ordelete
运算符,因此它必须依靠跟踪变量范围来找出何时不再使用变量(以及对这些原因变量的引用)。
如果你认为你做了一件好事,那就特别糟糕了。我在“优化”这样的代码后看到了这种错误:
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);
在 Eclipse 中获取此错误的一种方法:
A
在 中定义一个类src/test/java
。B
的类。src/main/java
A
结果:Eclipse 将编译代码,但 maven 会给出“找不到符号”。
根本原因:Eclipse 使用主树和测试树的组合构建路径。不幸的是,它不支持对 Eclipse 项目的不同部分使用不同的构建路径,而这正是 Maven 所需要的。
解决方案 :
解决了
使用 IntelliJ
选择Build -> Rebuild Project将解决它
“找不到”意味着编译器找不到合适的变量、方法、类等……如果你得到那个错误消息,首先你要找到得到错误消息的代码行……然后你会能够找到在使用之前没有定义的变量、方法或类。确认后初始化该变量、方法或类可以用于以后的需求...考虑以下示例。
我将创建一个演示类并打印一个名称...
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);
}
}
现在看看新的输出......
好的 成功解决了那个错误..同时,如果你能得到“找不到方法”或“找不到类”的东西,首先,定义一个类或方法,然后使用它..
如果您在其他地方的构建中遇到此错误,而您的 IDE 说一切都很好,请检查您是否在两个地方使用相同的 Java 版本。
例如,Java 7 和 Java 8 具有不同的 API,因此在较旧的 Java 版本中调用不存在的 API 会导致此错误。
如果 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
正如人们上面提到的那样,可能存在各种情况。有几件事帮助我解决了这个问题。
如果您使用 IntelliJ
File -> 'Invalidate Caches/Restart'
或者
被引用的类在另一个项目中,并且该依赖项未添加到我项目的 Gradle 构建文件中。所以我添加了依赖项
compile project(':anotherProject')
它奏效了。!
我也遇到了这个错误。(为此我用谷歌搜索并被定向到此页面)
问题:我正在从另一个项目 B 中定义的类调用项目 A 的类中定义的静态方法。我收到以下错误:
error: cannot find symbol
解决方案:我解决了这个问题,首先构建定义方法的项目,然后构建调用方法的项目。
就我而言 - 我必须执行以下操作:
context.xml
文件从src/java/package
目录移动resource
(IntelliJ IDE)target
目录。您使用 maven compile 编译了代码,然后使用 maven test 运行它工作正常。现在,如果您更改了代码中的某些内容,然后没有编译就运行它,您将收到此错误。
解决方案:再次编译它,然后运行测试。对我来说,它是这样工作的。
我们在设置为 Gradle 多项目构建的 Java 项目中遇到错误。结果发现其中一个子项目缺少Gradle Java 库插件。这阻止了子项目的类文件对构建中的其他项目可见。
通过以下方式将Java库插件添加到子项目build.gradle
后,错误消失了:
plugins {
...
id 'java-library'
}
有关提示,请仔细查看引发错误的类名名称和行号,例如:Compilation failure [ERROR] \applications\xxxxx.java:[44,30] error: cannot find symbol
另一个原因是 java 版本不支持的方法说 jdk7 vs 8。检查你的 %JAVA_HOME%
回复: 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
包括所有预期的类,并且一切都可以编译。
现在,错误的含义是编译器无法理解定义符号的引用。或者只是编译器无法做到这一点。
如果您在其他地方的构建中遇到此错误,而您的 IDE 说一切都很好,那么请检查您是否在两个地方使用相同的 Java 版本。如果您在其他地方的构建中遇到此错误,并且您的 IDE 说一切正常,请检查两个地方是否使用了相同的 Java 版本。
例如,Java 7 和 Java 8 具有不同的 API,因此在较旧的 Java 版本中调用不存在的 API 会导致此错误。例如,Java 7 和 Java 8 有不同的 API,因此在较旧的 Java 版本中调用不存在的 API 会导致此错误。