请解释以下关于“无法找到符号”的错误:
此问题旨在成为关于Java中“无法找到符号”编译错误的综合问题。
答案 0 :(得分:356)
首先,它是编译错误 1 。这意味着要么在您的Java源代码中存在问题,或在编译它的方式上存在问题。
您的Java源代码包含以下内容:
true
,false
,class
,while
等。42
和'X'
以及"Hi mum!"
。+
,=
,{
等。Reader
,i
,toString
,processEquibalancedElephants
等。A"找不到符号"错误是关于标识符。编译代码时,编译器需要确定代码中每个标识符的含义。
A"找不到符号"错误意味着编译器无法执行此操作。您的代码似乎指的是编译器无法理解的内容。
作为第一个订单,只有一个原因。编译器查找了应该定义的所有位置,并且找不到定义。这可能是由许多事情引起的。常见的如下:
StringBiulder
而不是StringBuilder
。 Java不能也不会试图弥补拼写错误或输入错误。stringBuilder
而不是StringBuilder
。所有Java标识符都区分大小写。mystring
和my_string
不同。 (如果你坚持Java风格规则,你将在很大程度上受到这种错误的保护......)"someString".push()
2 "someString".length
或someArray.length()
。对于应该是类名的标识符:
也许您忘记了new
,如:
String s = String(); // should be 'new String()'
对于类型或实例似乎没有您希望拥有的成员的情况:
问题通常是上述的组合。例如,也许你"明星"已导入java.io.*
,然后尝试使用Files
而非java.nio
的{{1}}类...或许你打算写java.io
... 是 File
中的一个类。
以下是一个示例,说明不正确的变量范围如何导致"找不到符号"错误:
java.io
这将给出一个&#34;找不到符号&#34; for (int i = 0; i < strings.size(); i++) {
if (strings.get(i).equalsIgnoreCase("fnoord")) {
break;
}
}
if (i < strings.size()) {
...
}
语句中i
的错误。虽然我们之前声明了if
,但该声明只是i
语句及其正文的范围。 for
语句中对i
的引用无法查看 if
的声明。 超出范围。
(这里适当的修正可能是在循环中移动i
语句,或在循环开始之前声明if
。)
这是一个导致困惑的例子,其中拼写错误导致看似无法解释的错误&#34;找不到符号&#34;错误:
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
的先前声明超出范围< / em>在街区。
这是另一个&#34;无法找到符号&#34;由错字引起的错误。
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
。或者更好的是仍然使用Java构建工具;例如Ant,Maven,Gradle等。
还有一些其他更为模糊的原因......我将在下面讨论。
一般来说,您首先要弄清楚导致编译错误。
然后你想想你的代码应该说些什么。最后,您需要确定需要对源代码进行哪些更正才能完成所需的操作。
请注意,并非所有&#34;更正&#34;是正确的。考虑一下:
javac *.java
假设编译器说&#34;找不到符号&#34;为for (int i = 1; i < 10; i++) {
for (j = 1; j < 10; j++) {
...
}
}
。我有很多方法可以修复&#34;的是:
j
更改为for
- 可能是正确的。for (int j = 1; j < 10; j++)
循环或外部j
循环之前为for
添加声明 - 可能是正确的。for
循环中将j
更改为i
- 可能是错误的!关键是你需要来了解你的代码尝试做什么才能找到正确的解决方案。
以下是一些&#34;无法找到符号&#34;看起来似乎莫名其妙......直到你仔细观察。
不正确的依赖项:如果您使用的是管理构建路径和项目依赖项的IDE或构建工具,那么您可能在依赖项中犯了错误;例如遗漏了依赖关系,或选择了错误的版本。如果您使用的是构建工具(Ant,Maven,Gradle等),请检查项目的构建文件。如果您使用的是IDE,请检查项目的构建路径配置。
您没有重新编译:有时新的Java程序员不了解Java工具链是如何工作的,或者没有实现可重复的#34 ;构建过程&#34 ;;例如使用IDE,Ant,Maven,Gradle等。在这种情况下,程序员最终可能会追逐他的尾巴寻找由于未正确重新编译代码而导致实际的虚幻错误等...
较早的构建问题:早期构建可能会导致JAR文件缺少类。如果您使用构建工具,通常会注意到这种失败。但是,如果您从其他人那里获取JAR文件,则依赖于他们正确构建,并注意到错误。如果您怀疑这一点,请使用for
列出可疑JAR文件的内容。
IDE问题:人们已经报告了他们的IDE混淆并且IDE中的编译器找不到存在的类的情况......或者相反的情况。
如果IDE的缓存与文件系统不同步,则会发生这种情况。有IDE特定的方法来解决这个问题。
这可能是一个IDE错误。例如@Joel Costigliola描述了Eclipse不处理Maven&#34;测试&#34;树正确:see this answer。
重新定义系统类:我见过编译器抱怨tar -tvf
是一个未知符号的情况,如下所示
substring
事实证明,程序员已经创建了自己的String s = ...
String s1 = s.substring(1);
版本,并且他的版本没有定义String
方法。
课程:不要使用与公共库类相同的名称来定义自己的类!
Homoglyphs:如果您对源文件使用UTF-8编码,则可能使看起来的标识符相同,但实际上是不同的因为它们包含同形体。有关详细信息,请参阅this page。
您可以通过将自己限制为ASCII或Latin-1作为源文件编码,并将Java substring
转义为其他字符来避免这种情况。
1 - 如果, 在运行时异常或错误消息中看到这一点,那么您已将IDE配置为运行带有编译错误的代码,或者您的应用程序正在生成并在运行时编译代码。
2 - 土木工程的三个基本原则:水不会上坡,木板侧面更强,而且你不能推上一根绳子
答案 1 :(得分:21)
如果忘记new
:
String s = String();
与
String s = new String();
答案 2 :(得分:14)
“变量超出范围”的另一个例子
正如我已经看过几次这样的问题,也许还有一个例子就是非法的,即使它可能感觉没问题。
考虑以下代码:
if(somethingIsTrue()) {
String message = "Everything is fine";
} else {
String message = "We have an error";
}
System.out.println(message);
这是无效的代码。因为名为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);
}
“哦,有重复的代码,让我们拉出那条普通的线路” - &gt;它就在那里。
处理这种范围问题的最常见方法是将else-values预先分配给外部范围中的变量名称,然后在以下情况下重新分配:
String message = "We have an error";
if(somethingIsTrue()) {
message = "Everything is fine";
}
System.out.println(message);
答案 3 :(得分:8)
在Eclipse中获取此错误的一种方法:
A
。src/test/java
B
中定义另一个使用班级src/main/java
的班级A
。结果:Eclipse将编译代码,但是maven将给出&#34;找不到符号&#34;。
潜在原因:Eclipse正在使用主树和测试树的组合构建路径。不幸的是,它不支持为Eclipse项目的不同部分使用不同的构建路径,这是Maven所需要的。
解决方案:
答案 4 :(得分:3)
“找不到”表示编译器找不到合适的变量,方法,类等...如果您得到了错误提示,首先您要查找获得错误提示的代码行。那么在使用它之前,您将能够找到尚未定义的变量,方法或类。在确认初始化后,该变量,方法或类可用于以后的需求...请考虑以下示例。
我将创建一个演示类并打印名称...
class demo{
public static void main(String a[]){
System.out.print(name);
}
}
现在看看结果。
该错误表示“找不到变量名”。可以取消定义和初始化“名称”变量的值。实际上就是这样,
class demo{
public static void main(String a[]){
String name="smith";
System.out.print(name);
}
}
现在看看新的输出...
好,成功解决了这个错误。.同时,如果您得到“找不到方法”或“找不到类”的东西,请首先定义一个类或方法,然后再使用它。 >
答案 5 :(得分:2)
如果你在其他地方的构建中遇到这个错误,而你的IDE说一切都很好,那么检查你在两个地方都使用相同的Java版本。
例如,Java 7和Java 8具有不同的API,因此在较旧的Java版本中调用不存在的API会导致此错误。
答案 6 :(得分:1)
如果将eclipse Java构建路径映射到7、8,并且在Project pom.xml Maven属性java.version中提到Java版本高于(9、10、11等。),则需要更新7,8在pom.xml文件中。
在Eclipse中,如果Java映射到Java版本11,在pom.xml中,它映射到Java版本8,请通过在Eclipse IDE中执行以下步骤来将Eclipse支持更新为Java 11。 帮助->安装新软件->
将链接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构建步骤
答案 7 :(得分:1)
您使用maven compile编译了代码,然后使用maven测试运行了它。现在,如果您更改了代码中的某些内容,然后又不进行编译就运行它,则会收到此错误。
解决方案:再次编译它,然后运行测试。对我来说,它是这样工作的。
答案 8 :(得分:1)
就我而言-我必须执行以下操作:
context.xml
文件从src/java/package
移动到resource
目录(IntelliJ
IDE)target
目录。答案 9 :(得分:1)
已解决
选择构建-> 重建项目即可解决
答案 10 :(得分:0)
人们可能会提到各种情况。有几件事帮助我解决了这个问题。
如果您使用的是IntelliJ
File -> 'Invalidate Caches/Restart'
OR
被引用的类在另一个项目中,并且该依赖项未添加到我项目的Gradle构建文件中。所以我使用
添加了依赖项 compile project(':anotherProject')
成功了。 HTH!
答案 11 :(得分:0)
答案 12 :(得分:0)
我们在设置为Gradle多项目构建的Java项目中遇到了错误。原来,其中一个子项目缺少Gradle Java Library plugin。 这样可以防止子项目的类文件对构建中的其他项目可见。
按照以下方式将Java库插件添加到子项目的build.gradle
后,错误消失了:
plugins {
...
id 'java-library'
}
答案 13 :(得分:0)
对于提示,请仔细查看抛出错误的类名称和行号,例如: 编译失败 [ERROR] \ applications \ xxxxx.java:[44,30]错误:找不到符号
另一个原因是java版本的不支持的方法,例如jdk7 vs 8。 检查你的%JAVA_HOME%
答案 14 :(得分:0)
我也遇到了这个错误。 (我用Google搜索,我被引导到此页面)
问题:我在另一个项目B中定义的类中调用了项目A的类中定义的静态方法。 我收到以下错误:
error: cannot find symbol
解决方案:我通过首先构建定义方法的项目,然后是调用方法的项目来解决这个问题。
答案 15 :(得分:-1)
现在,错误的意思是编译器无法理解定义符号的引用。或者干脆编译器做不到这一点。
如果您在其他地方的构建中遇到此错误,而您的 IDE 表示一切正常,请检查您在两个地方使用的 Java 版本是否相同。 如果您在其他地方的构建中遇到此错误,并且您的 IDE 说一切正常,请检查两个地方是否使用相同的 Java 版本。
例如,Java 7 和 Java 8 具有不同的 API,因此调用旧 Java 版本中不存在的 API 会导致此错误。 例如,Java 7 和 Java 8 具有不同的 API,因此调用旧 Java 版本中不存在的 API 会导致此错误。
答案 16 :(得分:-1)
在将类文件导入我的新 Eclipse 项目(包括主类文件)后,我收到此错误。经过反复试验,我通过将导致此错误的类文件移动到我的 src 文件夹并将我的运行配置设置为我的主类的确切名称来修复它。