“Cannot find symbol”编译错误是什么意思?
1.“Cannot find symbol”错误是什么意思?
首先,它是编译错误1。这意味着,无论有在Java源代码中的问题,或有在你编译它的方式有问题。
您的Java源代码包含以下内容:
关键词:像true,false,class,while,等。
文字:像42和'X'和"Hi mum!"。
运营商和其他非字母数字标记:像+,=,{,等等。
标识符:像Reader,i,toString,processEquibalancedElephants,等。
注释和空白。
“Cannot find symbol”错误与标识符有关。编译代码时,编译器需要确定代码中每个标识符的含义。
“Cannot find symbol”错误意味着编译器无法执行此操作。您的代码似乎是指编译器无法理解的内容。
2.什么可能导致“Cannot find symbol”错误?
编译器查找了应该定义标识符的所有位置,并且找不到定义。这可能是由许多事情引起的。常见的如下:
对于标识符一般:也许你拼错了名字; 即StringBiulder代替StringBuilder。Java不能也不会尝试弥补拼写错误或输入错误。
也许你弄错了; 即stringBuilder代替StringBuilder。所有Java标识符都区分大小写。
也许你不恰当地使用了下划线; 即mystring和my_string不同。(如果你遵守Java风格规则,你将在很大程度上受到这种错误的保护...)
也许你正在尝试使用被宣称为“其他地方”的东西; 即在一个不同的上下文中,你隐含地告诉编译器。(一个不同的类?一个不同的范围?一个不同的包?一个不同的代码库?)
对于应引用变量的标识符:也许你忘了申报变量了。
也许变量声明在您尝试使用它时不在范围内。(见下面的例子)
对于应该是方法或字段名称的标识符:
也许您正在尝试引用未在父/祖先类或接口中声明的继承方法或字段。
也许您正在尝试将方法用作字段,反之亦然; 例如"someString".length或someArray.length()。
对于应该是类名的标识符:也许你忘了导入课程。
也许您使用了“星型”导入,但未在您导入的任何包中定义该类。
也许你忘记了new:
String s = String(); // should be 'new String()'
对于类型或实例似乎没有您期望的成员的情况:也许您已经声明了一个嵌套类或泛型参数,它们会影响您要使用的类型。
也许您正在隐藏静态或实例变量。
也许你导入了错误的类型; 例如,由于IDE完成或自动更正。
也许您正在使用(编译)错误版本的API。
也许您忘了将对象转换为适当的子类。
问题通常是上述的组合。例如,也许你“*”导入java.io.*,然后尝试使用Files类...这java.nio不是java.io。或许你打算写File...这是一个班级java.io。
以下是不正确的变量范围如何导致“Cannot find symbol”错误的示例:
for (int i = 0; i < strings.size(); i++) {
if (strings.get(i).equalsIgnoreCase("fnoord")) {
break;
}
}
if (i < strings.size()) {
...
}
这将i在if语句中给出“Cannot find symbol”错误。虽然我们之前已经声明i,但该声明仅适用于for声明及其正文。以参考i在if声明中无法看到的那个声明i。它超出了范围。
(这里适当的修正可能是if在循环中移动语句,或者i在循环开始之前声明。)
这是一个导致困惑的例子,其中拼写错误导致看似无法解释的“Cannot find symbol”错误:
for (int i = 0; i < 100; i++); {
System.out.println("i is " + i);
}
这将在println调用中显示i无法找到的编译错误。但是(我听到你说)我确实宣布了!
问题是之前的鬼鬼祟祟的分号{。Java语言将其定义为空语句。所以代码实际上意味着:
for (int i = 0; i < 100; i++);
{
System.out.println("i is " + i);
}
该{ ... }块不是for循环的主体,因此声明i不在块的范围内。
这是由拼写错误引起的“Cannot find symbol”错误的另一个示例。
int tmp = ...
int res = tmp(a + b);
尽管与先前的声明中,tmp在tmp(...)表达是错误的。编译器将查找一个名为的方法tmp,但不会找到一个方法。先前声明的tmp是变量的名称空间,而不是方法的名称空间。
在我遇到的例子中,程序员实际上已经遗漏了一个操作员。他打算写的是这样的:
int res = tmp * (a + b);
如果从命令行编译,编译器可能Cannot find symbol还有另一个原因。您可能只是忘记编译或重新编译其他类。举例来说,如果你有类Foo和Bar地方Foo使用Bar。如果您从未编译过Bar并且运行过javac Foo.java,则可能会发现编译器找不到该符号Bar。简单的答案就是Foo和Bar在一起; 例如javac Foo.java Bar.java或javac *.java。或者更好的是仍然使用Java构建工具; 例如Ant,Maven,Gradle等。
还有其他一些比较模糊的原因......我将在下面讨论。
3.如何修复这些错误?
一般来说,您首先要弄清楚导致编译错误的原因。
查看编译错误消息指示的文件中的行。
确定错误消息正在讨论的符号。
弄清楚为什么编译器说它Cannot find symbol; 往上看!
然后你想想你的代码应该说些什么。最后,您需要确定需要对源代码进行哪些更正才能执行您想要的操作。
请注意,并非每个“校正”都是正确的。考虑一下:
for (int i = 1; i < 10; i++) {
for (j = 1; j < 10; j++) {
...
}
}
假设编译器说“Cannot find symbol” j。有很多方法可以“修复”:
我可以改变内for到for (int j = 1; j < 10; j++)-可能是正确的。
我可以在内循环或外循环j 之前添加一个声明- 可能是正确的。forfor
我可以改变j,以i在内部for循环-可能是错的!
等等。
关键是您需要了解代码尝试执行的操作才能找到正确的修复方法。
4.模糊的原因
以下是一些“Cannot find symbol”看似莫名其妙的情况......直到你仔细观察。
1.不正确的依赖项:如果您使用的是管理构建路径和项目依赖项的IDE或构建工具,那么您可能在依赖项方面犯了错误; 例如,遗漏了依赖关系,或选择了错误的版本。如果您使用的是构建工具(Ant,Maven,Gradle等),请检查项目的构建文件。如果您使用的是IDE,请检查项目的构建路径配置。
2.您没有重新编译:有时会发生新的Java程序员不了解Java工具链的工作原理,或者没有实现可重复的“构建过程”; 例如,使用IDE,Ant,Maven,Gradle等。在这种情况下,程序员最终可能会追逐他的尾巴寻找一个虚幻的错误,这个错误实际上是由于没有正确地重新编译代码而导致的......等等......
3.较早的构建问题:早期构建可能以给出缺少类的JAR文件的方式失败。如果您使用构建工具,通常会注意到这样的故障。但是,如果您从其他人那里获取JAR文件,则依赖于它们正确构建并注意错误。如果您怀疑这一点,请使用tar -tvf列出可疑JAR文件的内容。
4.IDE问题:人们已经报告了他们的IDE混淆的情况,并且IDE中的编译器找不到存在的类......或者相反的情况。
如果IDE的缓存与文件系统不同步,则会发生这种情况。有IDE特定的方法来解决这个问题。
这可能是一个IDE错误。例如,@ Joel Costigliola描述了Eclipse无法正确处理Maven“测试”树的场景:请参阅此答案。
5.重新定义系统类:我已经看到了编译器抱怨这substring是一个未知符号的情况,如下所示
String s = ...
String s1 = s.substring(1);
事实证明,程序员已经创建了自己的版本,String并且他的类版本没有定义substring方法。
课程:不要使用与公共库类相同的名称来定义自己的类!
6. Homoglyphs: 如果您对源文件使用UTF-8编码,则可能具有看起来相同但实际上不同的标识符,因为它们包含同形字符。有关更多信息,请参阅此页面。
您可以通过将自己限制为ASCII或Latin-1作为源文件编码,并将Java \uxxxx转义用于其他字符来避免这种情况。