本文翻译自:What does a “Cannot find symbol” or “Cannot resolve symbol” error mean?
Please explain the following about "Cannot find symbol" and "Cannot resolve symbol" errors: 请解释以下有关“找不到符号”和“无法解析符号”错误的信息:
This question is designed to seed a comprehensive Q&A about these common compilation errors in Java. 该问题旨在对Java中的这些常见编译错误进行全面的问答。
参考:https://stackoom.com/question/1jrMO/找不到符号-或-无法解析符号-错误是什么意思
Not really. 并不是的。 "Cannot find symbol" and "Cannot resolve symbol" mean the same thing. “找不到符号”和“无法解析符号”含义相同。 Some Java compilers use one phrase, and some the other one. 一些Java编译器使用一个短语,而另一些则使用。
Firstly, it is a compilation error 1 . 首先,它是编译错误 1 。 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源代码中出现问题, 或者是你正在编译的方式有问题。
Your Java source code consists of the following things: 您的Java源代码包含以下内容:
true
, false
, class
, while
, and so on. 关键字:像true
, false
, class
, while
等等。 42
and 'X'
and "Hi mum!"
文字:例如42
和'X'
以及"Hi mum!"
. 。 +
, =
, {
, and so on. 运算符和其他非字母数字标记:像+
, =
, {
等等。 Reader
, i
, toString
, processEquibalancedElephants
, and so on. 标识符:如Reader
, i
, toString
, processEquibalancedElephants
等。 A "Cannot find symbol" error is about the identifiers. “找不到符号”错误与标识符有关。 When your code is compiled, the compiler needs to work out what each and every identifier in your code means. 编译代码时,编译器需要确定代码中每个标识符的含义。
A "Cannot find symbol" error means that the compiler cannot do this. “找不到符号”错误表示编译器无法执行此操作。 Your code appears to be referring to something that the compiler doesn't understand. 您的代码似乎是指编译器无法理解的内容。
As a first order, there is only one cause. 首先,只有一个原因。 The compiler looked in all of the places where the identifier should be defined, and it couldn't find the definition. 编译器查看了应该定义标识符的所有位置,但找不到该定义。 This could be caused by a number of things. 这可能是由多种原因引起的。 The common ones are as follows: 常见的如下:
StringBiulder
instead of StringBuilder
. 即StringBiulder
而不是StringBuilder
。 Java cannot and will not attempt to compensate for bad spelling or typing errors. Java无法也不会尝试弥补拼写错误或输入错误。 stringBuilder
instead of StringBuilder
. 即stringBuilder
而不是StringBuilder
。 All Java identifiers are case sensitive. 所有Java标识符均区分大小写。 mystring
and my_string
are different. 即mystring
和my_string
不同。 (If you stick to the Java style rules, you will be largely protected from this mistake ...) (如果您坚持使用Java样式规则,则将在很大程度上避免出现此错误...) For identifiers that should be method or field names: 对于应为方法或字段名称的标识符:
"someString".push()
2 . 例如"someString".push()
2 。 "someString".length
or someArray.length()
. 例如"someString".length
或someArray.length()
。 Perhaps you are mistakenly operating on an array rather than array element; 也许您是错误地对数组而不是数组元素进行操作。 eg 例如
String strings[] = ... if (strings.charAt(3)) { ... } // maybe that should be 'strings[0].charAt(3)'
For identifiers that should be class names: 对于应为类名的标识符:
Perhaps you forgot a new
as in: 也许您忘记了以下new
:
String s = String(); // should be 'new String()'
For cases where type or instance doesn't appear to have the member you were expecting it to have: 对于类型或实例似乎没有成员的情况,您希望它具有:
The problem is often a combination of the above. 问题通常是上述情况的组合。 For example, maybe you "star" imported java.io.*
and then tried to use the Files
class ... which is in java.nio
not java.io
. 例如,也许您“星标”了导入的java.io.*
,然后尝试使用Files
类...,它在java.nio
而不是java.io
。 Or maybe you meant to write File
... which is a class in java.io
. 也许您打算写File
...这是 java.io
一个类。
Here is an example of how incorrect variable scoping can lead to a "Cannot find symbol" error: 这是一个示例,说明变量作用域范围不正确会如何导致“找不到符号”错误:
List strings = ...
for (int i = 0; i < strings.size(); i++) {
if (strings.get(i).equalsIgnoreCase("fnord")) {
break;
}
}
if (i < strings.size()) {
...
}
This will give a "Cannot find symbol" error for i
in the if
statement. 这将使“无法找到符号”错误i
在if
声明。 Though we previously declared i
, that declaration is only in scope for the for
statement and its body. 尽管我们之前曾声明过i
,但该声明仅在 for
语句及其主体的范围内 。 The reference to i
in the if
statement cannot see that declaration of i
. 在if
语句中对i
的引用看不到 i
声明。 It is out of scope . 它超出范围 。
(An appropriate correction here might be to move the if
statement inside the loop, or to declare i
before the start of the loop.) (这里的适当修正可能是将if
语句移入循环,或在循环开始之前声明i
。)
Here is an example that causes puzzlement where a typo leads to a seemingly inexplicable "Cannot find symbol" error: 这是一个引起困惑的示例,其中的错别字导致看似莫名的“找不到符号”错误:
for (int i = 0; i < 100; i++); {
System.out.println("i is " + i);
}
This will give you a compilation error in the println
call saying that i
cannot be found. 这会给你一个编译错误的println
电话,说i
无法找到。 But (I hear you say) I did declare it! 但是(我听到你说)我确实宣布了!
The problem is the sneaky semicolon ( ;
) before the {
. 问题是{
之前的冒号( ;
)。 The Java language syntax defines a semicolon in that context to be an empty statement . Java语言语法在该上下文中将分号定义为空语句 。 The empty statement then becomes the body of the for
loop. 然后,空语句将成为for
循环的主体。 So that code actually means this: 因此该代码实际上意味着:
for (int i = 0; i < 100; i++);
// The previous and following are separate statements!!
{
System.out.println("i is " + i);
}
The { ... }
block is NOT the body of the for
loop, and therefore the previous declaration of i
in the for
statement is out of scope in the block. { ... }
块不是for
循环的主体,因此for
语句中i
的先前声明超出了该块的范围 。
Here is another example of "Cannot find symbol" error that is caused by a typo. 这是由错字引起的“找不到符号”错误的另一个示例。
int tmp = ...
int res = tmp(a + b);
Despite the previous declaration, the tmp
in the tmp(...)
expression is erroneous. 尽管与先前的声明中, tmp
在tmp(...)
的表达是错误的。 The compiler will look for a method called tmp
, and won't find one. 编译器将寻找一种名为tmp
的方法,但找不到。 The previously declared tmp
is in the namespace for variables, not the namespace for methods. 先前声明的tmp
在变量的名称空间中,而不在方法的名称空间中。
In the example I came across, the programmer had actually left out an operator. 在我遇到的示例中,程序员实际上省略了一个运算符。 What he meant to write was this: 他的意思是这样写的:
int res = tmp * (a + b);
There is another reason why the compiler might not find a symbol if you are compiling from the command line. 如果从命令行进行编译,则编译器可能找不到符号还有另一个原因。 You might simply have forgotten to compile or recompile some other class. 您可能只是忘了编译或重新编译其他类。 For example, if you have classes Foo
and Bar
where Foo
uses Bar
. 例如,如果您有Foo
和Bar
类,其中Foo
使用Bar
。 If you have never compiled Bar
and you run javac Foo.java
, you are liable to find that the compiler can't find the symbol Bar
. 如果您从未编译过Bar
并且运行了javac Foo.java
,则很可能会发现编译器找不到Bar
的符号。 The simple answer is to compile Foo
and Bar
together; 简单的答案是将Foo
和Bar
一起编译。 eg javac Foo.java Bar.java
or javac *.java
. 例如javac Foo.java Bar.java
或javac *.java
。 Or better still use a Java build tool; 或者最好还是使用Java构建工具; eg Ant, Maven, Gradle and so on. 例如Ant,Maven,Gradle等。
There are some other more obscure causes too ... which I will deal with below. 还有一些其他更晦涩的原因...我将在下面处理。
Generally speaking, you start out by figuring out what caused the compilation error. 一般来说,首先要弄清楚是什么导致了编译错误。
Then you think about what your code is supposed to be saying. 然后,您考虑一下您的代码应该说什么。 Then finally you work out what correction you need to make to your source code to do what you want. 然后,最后您确定需要对源代码进行哪些更正以执行所需的操作。
Note that not every "correction" is correct. 请注意,并非每个“更正”都是正确的。 Consider this: 考虑一下:
for (int i = 1; i < 10; i++) {
for (j = 1; j < 10; j++) {
...
}
}
Suppose that the compiler says "Cannot find symbol" for j
. 假设编译器为j
说“找不到符号”。 There are many ways I could "fix" that: 我可以通过多种方式“修复”该问题:
for
to for (int j = 1; j < 10; j++)
- probably correct. 我可以将for
的内部变量更改for (int j = 1; j < 10; j++)
-可能是正确的。 j
before the inner for
loop, or the outer for
loop - possibly correct. 我可以在内部for
循环或外部for
循环之前添加j
的声明-可能是正确的。 j
to i
in the inner for
loop - probably wrong! 我可以在内部for
循环中将j
更改为i
可能错了! The point is that you need to understand what your code is trying to do in order to find the right fix. 关键是您需要了解您的代码正在尝试做什么才能找到正确的修复程序。
Here are a couple of cases where the "Cannot find symbol" is seemingly inexplicable ... until you look closer. 在一些情况下,“找不到符号”似乎无法解释……直到您仔细观察。
Incorrect dependencies : If you are using an IDE or a build tool that manages the build path and project dependencies, you may have made a mistake with the dependencies; 不正确的依赖关系 :如果您使用的是IDE或管理构建路径和项目依赖关系的构建工具,则可能是错误的依赖关系; eg left out a dependency, or selected the wrong version. 例如遗漏了一个依赖项,或者选择了错误的版本。 If you are using a build tool (Ant, Maven, Gradle, etc), check the project's build file. 如果您使用的是构建工具(Ant,Maven,Gradle等),请检查项目的构建文件。 If you are using an IDE, check the project's build path configuration. 如果使用的是IDE,请检查项目的构建路径配置。
You are not recompiling : It sometimes happens that new Java programmers don't understand how the Java tool chain works, or haven't implemented a repeatable "build process"; 您无需重新编译 :有时候,新Java程序员可能不了解Java工具链的工作方式,或者没有实现可重复的“构建过程”; eg using an IDE, Ant, Maven, Gradle and so on. 例如使用IDE,Ant,Maven,Gradle等。 In such a situation, the programmer can end up chasing his tail looking for an illusory error that is actually caused by not recompiling the code properly, and the like ... 在这种情况下,程序员最终可能会追尾寻找一个虚幻的错误,该错误实际上是由于未正确地重新编译代码而导致的,等等。
An earlier build problem : It is possible that an earlier build failed in a way that gave a JAR file with missing classes. 较早的构建问题 : 较早的构建可能会失败,从而导致JAR文件缺少类。 Such a failure would typically be noticed if you were using a build tool. 如果使用构建工具,通常会注意到这种故障。 However if you are getting JAR files from someone else, you are dependent on them building properly, and noticing errors. 但是,如果要从其他人那里获取JAR文件,则取决于它们是否可以正确构建并注意到错误。 If you suspect this, use tar -tvf
to list the contents of the suspect JAR file. 如果您怀疑这一点,请使用tar -tvf
列出可疑JAR文件的内容。
IDE issues : People have reported cases where their IDE gets confused and the compiler in the IDE cannot find a class that exists ... or the reverse situation. IDE问题 :人们报告说,他们的IDE感到困惑,并且IDE中的编译器找不到存在的类……或相反的情况。
This could happen if the IDE has been configured with the wrong JDK version. 如果IDE配置了错误的JDK版本,则可能会发生这种情况。
This could happen if the IDE's caches get out of sync with the file system. 如果IDE的缓存与文件系统不同步,则可能发生这种情况。 There are IDE specific ways to fix that. 有特定于IDE的方法可以解决此问题。
This could be an IDE bug. 这可能是一个IDE错误。 For instance @Joel Costigliola describes a scenario where Eclipse does not handle a Maven "test" tree correctly: see this answer . 例如,@ Joel Costigliola描述了Eclipse无法正确处理Maven“测试”树的情况: 请参见此答案 。
Android issues : When you are programming for Android, and you have "Cannot find symbol" errors related to R
, be aware that the R
symbols are defined by the context.xml
file. Android问题 :当您使用Android进行编程时,遇到与R
相关的“找不到符号”错误,请注意, R
符号是由context.xml
文件定义的。 Check that your context.xml
file is correct and in the correct place, and that the corresponding R
class file has been generated / compiled. 检查您的context.xml
文件是正确的并且在正确的位置,并且已经生成/编译了相应的R
类文件。 Note that the Java symbols are case sensitive, so the corresponding XML ids are be case sensitive too. 请注意,Java符号区分大小写,因此相应的XML ID也区分大小写。
Other symbol errors on Android are likely to be due to previously mention reasons; Android上的其他符号错误可能是由于前面提到的原因引起的; eg missing or incorrect dependencies, incorrect package names, method or fields that don't exist in a particular API version, spelling / typing errors, and so on. 例如,缺少或不正确的依赖项,不正确的软件包名称,特定API版本中不存在的方法或字段,拼写/键入错误等。
Redefining system classes : I've seen cases where the compiler complains that substring
is an unknown symbol in something like the following 重新定义系统类 :我见过一些编译器抱怨substring
是未知符号的情况,如下所示
String s = ... String s1 = s.substring(1);
It turned out that the programmer had created their own version of String
and that his version of the class didn't define a substring
methods. 事实证明,程序员创建了自己的String
版本,而他的类版本未定义substring
方法。
Lesson: Don't define your own classes with the same names as common library classes! 课程:不要用与通用库类相同的名称定义自己的类!
Homoglyphs: If you use UTF-8 encoding for your source files, it is possible to have identifiers that look the same, but are in fact different because they contain homoglyphs. 同源符号:如果对源文件使用UTF-8编码,则可能具有看起来相同但实际上不同的标识符,因为它们包含同源符号。 See this page for more information. 有关更多信息,请参见此页面 。
You can avoid this by restricting yourself to ASCII or Latin-1 as the source file encoding, and using Java \\uxxxx
escapes for other characters. 通过将自己限制为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. 1 -如果,或许,你也看到这个运行时异常或错误信息,那么无论你配置你的IDE来运行代码编译错误,或者您的应用程序生成和编译代码..在运行时。
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 string . 2-土木工程的三个基本原则:水不上坡,木板在其侧面更坚固,并且您不能用力压绳子 。
You'll also get this error if you forget a new
: 如果您忘记了一个new
也会得到此错误:
String s = String();
versus 与
String s = new String();
because the call without the new
keyword will try and look for a (local) method called String
without arguments - and that method signature is likely not defined. 因为没有new
关键字的调用将尝试查找不带参数的String
的(本地)方法-并且该方法签名可能未定义。
One more example of 'Variable is out of scope' “变量超出范围”的另一个示例
As I've seen that kind of questions a few times already, maybe one more example to what's illegal even if it might feel okay. 正如我已经看过几次这样的问题一样,即使感觉还可以,也许还有另一个例子说明什么是非法的。
Consider this code: 考虑以下代码:
if(somethingIsTrue()) {
String message = "Everything is fine";
} else {
String message = "We have an error";
}
System.out.println(message);
That's invalid code. 那是无效的代码。 Because neither of the variables named message
is visible outside of their respective scope - which would be the surrounding brackets {}
in this case. 因为没有两个名为message
的变量在它们各自的作用域之外可见-在这种情况下,将用括号{}
括起来。
You might say: "But a variable named message is defined either way - so message is defined after the if
". 您可能会说:“但是以任何一种方式都定义了一个名为message的变量-因此message 是在if
后面定义的。
But you'd be wrong. 但是你会错的。
Java has no free()
or delete
operators, so it has to rely on tracking variable scope to find out when variables are no longer used (together with references to these variables of cause). Java没有free()
或delete
运算符,因此它必须依靠跟踪变量范围来确定何时不再使用变量(以及对这些cause变量的引用)。
It's especially bad if you thought you did something good. 如果您认为自己做得很好,那就特别糟糕。 I've seen this kind of error after "optimizing" code like this: 在“优化”如下代码后,我已经看到这种错误:
if(somethingIsTrue()) {
String message = "Everything is fine";
System.out.println(message);
} else {
String message = "We have an error";
System.out.println(message);
}
"Oh, there's duplicated code, let's pull that common line out" -> and there it it. “哦,有重复的代码,让我们拉出这条共同的线”->到那里。
The most common way to deal with this kind of scope-trouble would be to pre-assign the else-values to the variable names in the outside scope and then reassign in if: 处理这种范围问题的最常见方法是将else值预先分配给外部范围中的变量名,然后在以下情况下重新分配:
String message = "We have an error";
if(somethingIsTrue()) {
message = "Everything is fine";
}
System.out.println(message);
If you're getting this error in the build somewhere else, while your IDE says everything is perfectly fine, then check that you are using the same Java versions in both places. 如果您在其他地方的构建中遇到此错误,而您的IDE表示一切都很好,请检查两个地方是否使用相同的Java版本。
For example, Java 7 and Java 8 have different APIs, so calling a non-existent API in an older Java version would cause this error. 例如,Java 7和Java 8具有不同的API,因此在较旧的Java版本中调用不存在的API会导致此错误。
One way to get this error in Eclipse : 在Eclipse中获得此错误的一种方法:
A
in src/test/java
. 在src/test/java
定义A
类。 B
in src/main/java
that uses class A
. 在src/main/java
中定义另一个使用类A
类B
Result : Eclipse will compile the code, but maven will give "Cannot find symbol". 结果:Eclipse将编译代码,但是maven将给出“找不到符号”。
Underlying cause : Eclipse is using a combined build path for the main and test trees. 潜在原因:Eclipse对主树和测试树使用了组合的构建路径。 Unfortunately, it does not support using different build paths for different parts of an Eclipse project, which is what Maven requires. 不幸的是,它不支持为Eclipse项目的不同部分使用不同的构建路径,而这正是Maven所需要的。
Solution : 解决方案: