What does a "Cannot find symbol" compilation error mean?
Please explain the following about the "Cannot find symbol" error:
This question is designed to be a comprehensive question about "cannot find symbol" compilation errors in Java.
1. What does a "Cannot find symbol" error mean?
Firstly, it is a compilation error1. 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.
Your Java source code consists of the following things:
true
, false
, class
, while
, and so on. 42
and 'X'
and "Hi mum!"
. +
, =
, {
, and so on. Reader
, i
, toString
, processEquibalancedElephants
, and so on. 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.
2. What can cause a "Cannot find symbol" error?
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
. Java cannot and will not attempt to compensate for bad spelling or typing errors. stringBuilder
instead of StringBuilder
. All Java identifiers are case sensitive. mystring
and my_string
are different. (If you stick to the Java style rules, you will be largely protected from this mistake ...) "someString".length
or someArray.length()
. For identifiers that should be class names:
Perhaps you forgot a new
as in:
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
. Or maybe you meant to write File
... which is a class in java.io
.
Here is an example of how incorrect variable scoping can lead to a "Cannot find symbol" error:
for (int i = 0; i < strings.size(); i++) {
if (strings.get(i).equalsIgnoreCase("fnoord")) {
break;
}
}
if (i < strings.size()) {
...
}
This will give a "Cannot find symbol" error for i
in the if
statement. Though we previously declared i
, that declaration is only in scope for the for
statement and its body. The reference to i
in the if
statement cannot see that declaration of 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.)
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. But (I hear you say) I did declare it!
The problem is the sneaky semicolon before the {
. The Java language defines that to be an empty statement. So that code actually means this:
for (int i = 0; i < 100; i++);
{
System.out.println("i is " + i);
}
The { ... }
block is NOT the body of the for
loop, so the declaration of i
is not in scope in the the block.
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. The compiler will look for a method called tmp
, and won't find one. The previously declared tmp
is in the namespace for variables, not the namespace for methods.
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
. 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
. The simple answer is to Foo
and Bar
together; eg javac Foo.java Bar.java
or javac *.java
. Or better still use a Java build tool; eg Ant, Maven, Gradle and so on.
There are some other more obscure causes too ... which I will deal with below.
3. How do I fix these errors ?
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
. There are many ways I could "fix" that:
for
to for (int j = 1; j < 10; j++)
- probably correct. j
before the inner for
loop, or the outer for
loop - possibly correct. j
to i
in the inner for
loop - probably wrong! The point is that you need to understand what your code is trying to do in order to find the right fix.
4. Obscure causes
Here are a couple of cases where the "Cannot find symbol" is seemingly inexplicable ... until you look closer.
You are looking at the wrong source code : It often happens that a new Java programmers don't understand how the Java tool chain works, or haven't implemented a repeatable "build process"; eg using an IDE, Ant, Maven, Gradle and so on. 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 ...
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.
This can happen if the IDE's caches get out of sync with the file system. There are IDE specific ways to fix that.
This could be an IDE bug. For instance @Joel Costigliola describes a scenario where Eclipse does not handle a Maven "test" tree correctly: see this answer .
Redefining system classes : I've seen cases where the compiler complains that substring
is an unknown symbol in something like the following
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.
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. 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.
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.
You'll also get this error if you forget a new
:
String s = String();
versus
String s = 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.
You might say: "But a variable named message is defined either way - so message is defined after the 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).
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:
String message = "We have an error";
if(somethingIsTrue()) {
message = "Everything is fine";
}
System.out.println(message);
链接地址: http://www.djcxy.com/p/9374.html
上一篇: 测试一个字符串的子字符串?
下一篇: “找不到符号”编译错误是什么意思?