“找不到符号”或“无法解析符号”错误是什么意思?

本文翻译自: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: 请解释以下有关“找不到符号”和“无法解析符号”错误的信息:

  • What does they mean? 什么意思
  • What things can cause them? 什么事会导致它们?
  • How does the programmer go about fixing them? 程序员如何进行修复?

This question is designed to seed a comprehensive Q&A about these common compilation errors in Java. 该问题旨在对Java中的这些常见编译错误进行全面的问答。


#1楼

参考:https://stackoom.com/question/1jrMO/找不到符号-或-无法解析符号-错误是什么意思


#2楼

0. Is there any difference between the two errors? 0.两种错误之间有区别吗?

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编译器使用一个短语,而另一些则使用。

1. What does a "Cannot find symbol" error mean? 1.“找不到符号”错误是什么意思?

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源代码包含以下内容:

  • Keywords: like true , false , class , while , and so on. 关键字:像truefalseclasswhile等等。
  • Literals: like 42 and 'X' and "Hi mum!" 文字:例如42'X'以及"Hi mum!" .
  • Operators and other non-alphanumeric tokens: like + , = , { , and so on. 运算符和其他非字母数字标记:像+={ 等等。
  • Identifiers: like Reader , i , toString , processEquibalancedElephants , and so on. 标识符:如ReaderitoStringprocessEquibalancedElephants等。
  • Comments and whitespace. 注释和空格。

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? 2.什么会导致“找不到符号”错误?

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: 常见的如下:

  • For identifiers in general: 对于一般的标识符:
    • Perhaps you spelled the name incorrectly; 也许您拼错了名字; ie StringBiulder instead of StringBuilder . StringBiulder而不是StringBuilder Java cannot and will not attempt to compensate for bad spelling or typing errors. Java无法也不会尝试弥补拼写错误或输入错误。
    • Perhaps you got the case wrong; 也许你错了。 ie stringBuilder instead of StringBuilder . stringBuilder而不是StringBuilder All Java identifiers are case sensitive. 所有Java标识符均区分大小写。
    • Perhaps you used underscores inappropriately; 也许您不恰当地使用了下划线; ie mystring and my_string are different. mystringmy_string不同。 (If you stick to the Java style rules, you will be largely protected from this mistake ...) (如果您坚持使用Java样式规则,则将在很大程度上避免出现此错误...)
    • Perhaps you are trying to use something that was declared "somewhere else"; 也许您正在尝试使用被声明为“其他地方”的东西; ie in a different context to where you have implicitly told the compiler to look. 即在与您隐式告诉编译器查看的位置不同的上下文中。 (A different class? A different scope? A different package? A different code-base?) (不同的类?不同的作用域?不同的包?不同的代码库?)
  • For identifiers that should refer to variables: 对于应引用变量的标识符:
    • Perhaps you forgot to declare the variable. 也许您忘记了声明变量。
    • Perhaps the variable declaration is out of scope at the point you tried to use it. 变量声明在您尝试使用它时可能超出范围。 (See example below) (请参见下面的示例)
  • For identifiers that should be method or field names: 对于应为方法或字段名称的标识符:

    • Perhaps you are trying to refer to an inherited method or field that wasn't declared in the parent / ancestor classes or interfaces. 也许您正在尝试引用在父/祖先类或接口中未声明的继承方法或字段。
    • Perhaps you are trying to refer to a method or field that does not exist (ie has not been declared) in the type you are using; 也许您正在尝试引用所使用的类型中不存在(即尚未声明)的方法或字段; eg "someString".push() 2 . 例如"someString".push() 2
    • Perhaps you are trying to use a method as a field, or vice versa; 也许您正在尝试将方法用作字段,反之亦然; eg "someString".length or someArray.length() . 例如"someString".lengthsomeArray.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 to import the class. 也许您忘记了导入课程。
    • Perhaps you used "star" imports, but the class isn't defined in any of the packages that you imported. 也许您使用了“星号”导入,但是在您导入的任何软件包中均未定义该类。
    • 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: 对于类型或实例似乎没有成员的情况,您希望它具有:

    • Perhaps you have declared a nested class or a generic parameter that shadows the type you were meaning to use. 也许您已经声明了一个嵌套类或泛型参数,该类掩盖了您打算使用的类型。
    • Perhaps you are shadowing a static or instance variable. 也许您正在隐藏静态变量或实例变量。
    • Perhaps you imported the wrong type; 也许您输入了错误的类型; eg due to IDE completion or auto-correction. 例如由于IDE完成或自动更正。
    • Perhaps you are using (compiling against) the wrong version of an API. 也许您正在使用(针对)错误版本的API。
    • Perhaps you forgot to cast your object to an appropriate subclass. 也许您忘记了将对象转换为适当的子类。

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. 这将使“无法找到符号”错误iif声明。 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. 尽管与先前的声明中, tmptmp(...)的表达是错误的。 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 . 例如,如果您有FooBar类,其中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; 简单的答案是将FooBar一起编译。 eg javac Foo.java Bar.java or javac *.java . 例如javac Foo.java Bar.javajavac *.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. 还有一些其他更晦涩的原因...我将在下面处理。

3. How do I fix these errors ? 3.如何解决这些错误?

Generally speaking, you start out by figuring out what caused the compilation error. 一般来说,首先要弄清楚是什么导致了编译错误。

  • Look at the line in the file indicated by the compilation error message. 查看编译错误消息指示的文件中的行。
  • Identify which symbol that the error message is talking about. 确定错误消息正在谈论的符号。
  • Figure out why the compiler is saying that it cannot find the symbol; 弄清楚编译器为什么说找不到符号; 为什么 see above! 往上看!

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: 我可以通过多种方式“修复”该问题:

  • I could change the inner for to for (int j = 1; j < 10; j++) - probably correct. 我可以将for的内部变量更改for (int j = 1; j < 10; j++) -可能是正确的。
  • I could add a declaration for j before the inner for loop, or the outer for loop - possibly correct. 我可以在内部for循环或外部for循环之前添加j的声明-可能是正确的。
  • I could change j to i in the inner for loop - probably wrong! 我可以在内部for循环中将j更改为i可能错了!
  • and so on. 等等。

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 4.原因不明

Here are a couple of cases where the "Cannot find symbol" is seemingly inexplicable ... until you look closer. 在一些情况下,“找不到符号”似乎无法解释……直到您仔细观察。

  1. 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,请检查项目的构建路径配置。

  2. 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 ... 在这种情况下,程序员最终可能会追尾寻找一个虚幻的错误,该错误实际上是由于未正确地重新编译代码而导致的,等等。

  3. 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文件的内容。

  4. 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“测试”树的情况: 请参见此答案

  5. 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版本中不存在的方法或字段,拼写/键入错误等。

  6. 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! 课程:不要用与通用库类相同的名称定义自己的类!

  7. 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-土木工程的三个基本原则:水不上坡,木板在其侧面更坚固,并且您不能用力压绳子


#3楼

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的(本地)方法-并且该方法签名可能未定义。


#4楼

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);

#5楼

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会导致此错误。


#6楼

One way to get this error in Eclipse : 在Eclipse中获得此错误的一种方法:

  1. Define a class A in src/test/java . src/test/java定义A类。
  2. Define another class B in src/main/java that uses class A . src/main/java中定义另一个使用类AB

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 : 解决方案:

  1. Don't define your dependencies that way; 不要以这种方式定义依赖项; ie don't make this mistake. 即不要犯这个错误。
  2. Regularly build your codebase using Maven so that you pick up this mistake early. 定期使用Maven构建代码库,以便您尽早发现此错误。 One way to do that is to use a CI server. 一种方法是使用CI服务器。

你可能感兴趣的:(java,compiler-errors)