请解释以下关于“无法找到符号”,“无法解析符号”或“符号未找到”的错误(在Java中):
它们是什么意思? 什么东西会引起它们? 程序员如何着手修复它们?
本问题旨在针对Java中常见的编译错误进行全面的问答。
请解释以下关于“无法找到符号”,“无法解析符号”或“符号未找到”的错误(在Java中):
它们是什么意思? 什么东西会引起它们? 程序员如何着手修复它们?
本问题旨在针对Java中常见的编译错误进行全面的问答。
当前回答
我们在一个Java项目中得到了一个错误,该项目被设置为Gradle多项目构建。结果发现其中一个子项目缺少Gradle Java Library插件。 这阻止了子项目的类文件对构建中的其他项目可见。
在将Java库插件添加到子项目的构建之后。用下面的方法Gradle,错误就消失了:
plugins {
...
id 'java-library'
}
其他回答
回复:4.4:Stephen C的优秀回答中的一个早期构建问题:
我在开发osgi应用程序时遇到过这种情况。 我有一个java项目a,它依赖于B。 在建造B时,出现了错误:
Compilation failure: org.company.projectA.bar.xyz does not exist
但是在eclipse中,根本不存在编译问题。
调查 当我在A.jar中查看时,有org.company.projectA.foo.abc的类,但没有org.company.projectA.bar.xyz的类。
缺少类的原因是,在A/pom.xml中,有一个导出相关包的条目。
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
...
<configuration>
<instructions>
....
<Export-Package>org.company.projectA.foo.*</Export-Package>
</instructions>
</configuration>
</plugin>
解决方案 像这样添加缺少的包:
<Export-Package>org.company.projectA.foo.*,org.company.projectA.bar.*</Export-Package>
重建一切。
现在,A.jar包含了所有预期的类,所有的东西都编译好了。
您使用maven compile编译代码,然后使用maven test运行它,结果很好。现在,如果你在代码中改变了一些东西,然后在没有编译的情况下运行它,你会得到这个错误。
解决方案:再次编译,然后运行测试。对我来说是这样的。
我们在一个Java项目中得到了一个错误,该项目被设置为Gradle多项目构建。结果发现其中一个子项目缺少Gradle Java Library插件。 这阻止了子项目的类文件对构建中的其他项目可见。
在将Java库插件添加到子项目的构建之后。用下面的方法Gradle,错误就消失了:
plugins {
...
id 'java-library'
}
0. 这些错误之间有什么区别吗?
不是真的。“找不到符号”,“无法解析符号”和“找不到符号”都是同一个意思。(不同的Java编译器是由不同的人编写的,不同的人使用不同的措辞来表达相同的事情。)
1. “找不到符号”错误是什么意思?
首先,这是一个编译错误1。这意味着要么您的Java源代码有问题,要么您编译源代码的方式有问题。
您的Java源代码由以下内容组成:
关键词:喜欢类,同时,等等。 字面:像真,假,42,“X”和“嗨,妈妈!” 操作符和其他非字母数字标记:如+,=,{,等等。 标识符:比如Reader, i, toString, processEquibalancedElephants等等。 注释和空格。
“无法找到符号”错误是关于标识符的。编译代码时,编译器需要计算出代码中每个标识符的含义。
“不能找到符号”错误意味着编译器不能这样做。你的代码似乎引用了编译器不理解的东西。
2. 什么会导致“找不到符号”错误?
作为一阶,原因只有一个。编译器查看了所有应该定义标识符的地方,但找不到定义。这可能是由很多事情引起的。常见的有以下几种:
For identifiers in general: Perhaps you spelled the name incorrectly; i.e. StringBiulder instead of StringBuilder. Java cannot and will not attempt to compensate for bad spelling or typing errors. Perhaps you got the case wrong; i.e. stringBuilder instead of StringBuilder. All Java identifiers are case sensitive. Perhaps you used underscores inappropriately; i.e. mystring and my_string are different. (If you stick to the Java style rules, you will be largely protected from this mistake ...) Perhaps you are trying to use something that was declared "somewhere else"; i.e. 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 (i.e. has not been declared) in the type you are using; e.g. "rope".push()2. Perhaps you are trying to use a method as a field, or vice versa; e.g. "rope".length or someArray.length(). Perhaps you are mistakenly operating on an array rather than array element; e.g. 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: String s = String(); // should be 'new String()' Perhaps you are trying to import or otherwise use a class that has been declared in the default package; i.e. the one where classes with no package statements go. Hint: learn about packages. You should only use the default package for simple applications that consist of one class ... or at a stretch, one Java source file. For cases where type or instance doesn't appear to have the member (e.g. method or field) 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; e.g. due to IDE completion or auto-correction may have suggested java.awt.List rather than java.util.List. Perhaps you are using (compiling against) the wrong version of an API. Perhaps you forgot to cast your object to an appropriate subclass. Perhaps you have declared the variable's type to be a supertype of the one with the member you are looking for.
问题往往是以上两种情况的结合。例如,可能您“星型”导入了java.io。*然后尝试使用Files类…这是java语言。Nio不是java.io。或者你本想写File…这是java.io中的一个类。
下面是一个不正确的变量范围如何导致“无法找到符号”错误的例子:
List<String> strings = ...
for (int i = 0; i < strings.size(); i++) {
if (strings.get(i).equalsIgnoreCase("fnord")) {
break;
}
}
if (i < strings.size()) {
...
}
这将在if语句中为i给出“无法找到符号”错误。虽然我们之前声明了i,但该声明只适用于for语句及其语句体。if语句中对i的引用不能看到i的声明。它超出了作用域。
(这里适当的纠正可能是将if语句移动到循环内部,或者在循环开始之前声明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循环的体,因此之前for语句中i的声明超出了块的范围。
这是另一个由拼写错误引起的“找不到符号”错误的例子。
int tmp = ...
int res = tmp(a + b);
尽管有前面的声明,但是tmp(…)表达式中的tmp是错误的。编译器会寻找一个叫做tmp的方法,但是找不到。前面声明的tmp位于变量的名称空间中,而不是方法的名称空间中。
在我遇到的例子中,程序员实际上遗漏了一个操作符。他想写的是这样的:
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 compile Foo and Bar together; e.g. javac Foo.java Bar.java or javac *.java. Or better still use a Java build tool; e.g. Ant, Maven, Gradle and so on.
还有其他一些更隐晦的原因……我将在下面处理这个问题。
3.如何修复这些错误?
一般来说,首先要找出导致编译错误的原因。
查看文件中由编译错误消息指示的行。 确定错误消息谈论的是哪个符号。 弄清楚为什么编译器说它找不到符号;见上图!
然后考虑代码应该表达什么。最后,您需要确定需要对源代码进行哪些更正才能实现您想要的结果。
注意,并不是每一个“修正”都是正确的。考虑一下:
for (int i = 1; i < 10; i++) {
for (j = 1; j < 10; j++) {
...
}
}
假设编译器说“不能找到符号”的j。有很多方法我可以“修复”:
我可以把内部的for改成for (int j = 1;J < 10;j++) -可能是正确的。 我可以在内部的for循环之前添加一个关于j的声明,或者在外部的for循环之前——可能是正确的。 我可以在内部的for循环中将j改为I——可能是错误的! 等等。
关键在于,您需要了解您的代码试图做什么,以便找到正确的修复。
4. 模糊的原因
这里有几个例子,“找不到符号”似乎是令人费解的……直到你仔细看。
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; e.g. 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. If you are using an IDE, check the project's build path configuration. Cannot find symbol 'var': You are probably trying to compile source code that uses local variable type inference (i.e. a var declaration) with an older compiler or older --source level. The var was introduced in Java 10. Check your JDK version and your build files, and (if this occurs in an IDE), the IDE settings. You are not compiling / 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"; e.g. 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. Another example of this is when you use (Java 9+) java SomeClass.java to compile and run a class. If the class depends on another class that you haven't compiled (or recompiled), you are liable to get "Cannot resolve symbol" errors referring to the 2nd class. The other source file(s) are not automatically compiled. The java command's new "compile and run" mode is not designed for running programs with multiple source code files. An earlier build problem: It is possible that an earlier build failed in a way that gave a JAR file with missing classes. 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. If you suspect this, use tar -tvf to list the contents of the suspect JAR file. 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 could happen if the IDE has been configured with the wrong JDK version. This could 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 described a scenario where Eclipse did not handle a Maven "test" tree correctly: see this answer. (Apparently that particular bug was been fixed a long time ago.) 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. Check that your context.xml file is correct and in the correct place, and that the corresponding R class file has been generated / compiled. Note that the Java symbols are case sensitive, so the corresponding XML ids are be case sensitive too. Other symbol errors on Android are likely to be due to previously mention reasons; e.g. 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. Hiding 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. I've seen people do this with System, Scanner and other classes. Lesson: Don't define your own classes with the same names as common library classes! The problem can also be solved by using the fully qualified names. For example, in the example above, the programmer could have written: java.lang.String s = ... java.lang.String s1 = s.substring(1); 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 -如果你在运行时异常或错误消息中看到这一点,那么要么你已经配置了IDE来运行带有编译错误的代码,要么你的应用程序正在生成和编译代码。在运行时。 2 -土木工程的三个基本原则:水不会往山上流,木板在其一侧更坚固,你不能推绳子。
如果您在其他地方的构建中遇到此错误,而您的IDE表示一切正常,那么请检查您在两个地方使用的Java版本是否相同。
例如,Java 7和Java 8有不同的API,因此在较旧的Java版本中调用不存在的API会导致此错误。