请解释以下有关“找不到符号”和“无法解析符号”错误的信息:
什么意思 什么事会导致它们? 程序员如何进行修复? 该问题旨在对Java中的这些常见编译错误进行全面的问答。
0.两种错误之间有区别吗? 并不是的。“找不到符号”和“无法解析符号”含义相同。一些Java编译器使用一个短语,而另一些则使用。
1.“找不到符号”错误是什么意思? 首先,它是编译错误1。这意味着,无论有在Java源代码中的问题,或有在你编译它的方式有问题。
您的Java源代码包含以下内容:
关键词:喜欢true,false,class,while,等。 文字:like 42和'X'and "Hi mum!"。 运营商和其他非字母数字标记:像+,=,{,等等。 标识符:喜欢Reader,i,toString,processEquibalancedElephants,等。 注释和空格。 “找不到符号”错误与标识符有关。编译代码时,编译器需要确定代码中每个标识符的含义。
“找不到符号”错误表示编译器无法执行此操作。您的代码似乎是指编译器无法理解的内容。
2.什么会导致“找不到符号”错误? 首先,只有一个原因。编译器查看了应该定义标识符的所有位置,但找不到该定义。这可能是由多种原因引起的。常见的如下:
对于一般的标识符: 也许您拼错了名字;即StringBiulder代替StringBuilder。Java无法也不会尝试弥补拼写错误或输入错误。 也许你错了。即stringBuilder代替StringBuilder。所有Java标识符均区分大小写。 也许您不恰当地使用了下划线;即mystring和my_string不同。(如果您坚持使用Java样式规则,则将在很大程度上避免出现此错误...) 也许您正在尝试使用被声明为“其他地方”的东西;即在与您隐式告诉编译器查看的位置不同的上下文中。(不同的类?不同的作用域?不同的包?不同的代码库?) 对于应引用变量的标识符: 也许您忘记了声明变量。 变量声明在您尝试使用它时可能超出范围。(请参见下面的示例) 对于应为方法或字段名称的标识符:
也许您正在尝试引用在父/祖先类或接口中未声明的继承方法或字段。 也许您正在尝试引用所使用的类型中不存在(即尚未声明)的方法或字段;例如"someString".push()2。 也许您正在尝试将方法用作字段,反之亦然;例如"someString".length或someArray.length()。 也许您是错误地对数组而不是数组元素进行操作。例如
String strings[] = ... if (strings.charAt(3)) { ... } // maybe that should be 'strings[0].charAt(3)' 对于应为类名的标识符:
也许您忘记了导入课程。 也许您使用了“星号”导入,但是在您导入的任何软件包中均未定义该类。 也许您忘记了new:
String s = String(); // should be 'new String()' 对于类型或实例似乎没有成员的情况,您希望它具有:
也许您已经声明了一个嵌套类或泛型参数,该类掩盖了您打算使用的类型。 也许您正在隐藏静态变量或实例变量。 也许您输入了错误的类型;例如由于IDE完成或自动更正。 也许您正在使用(针对)错误版本的API。 也许您忘记了将对象转换为适当的子类。 问题通常是上述情况的组合。例如,也许您导入了“ star” java.io.*,然后尝试使用Filesclass中的java.nionot java.io。或者也许你打算写File... ...这是的一个类java.io。
这是一个示例,说明变量作用域范围不正确会如何导致“找不到符号”错误:
List strings = ...
for (int i = 0; i < strings.size(); i++) { if (strings.get(i).equalsIgnoreCase("fnord")) { break; } } if (i < strings.size()) { ... } 这将使“无法找到符号”错误i的if陈述。虽然我们先前声明i,该声明只是在范围上的for发言和它的身体。语句i中对的引用看不到的声明。它超出范围。ifi
(这里的一个适当的更正可能是将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循环的主体,因此i该for语句中的上一个声明超出了该块的范围。
这是由错字引起的“找不到符号”错误的另一个示例。
int tmp = ... int res = tmp(a + b); 尽管与先前的声明中,tmp在tmp(...)表达是错误的。编译器将寻找一种称为的方法tmp,但找不到。先前声明tmp的变量位于名称空间中,而不是方法的名称空间中。
在我遇到的示例中,程序员实际上省略了一个运算符。他的意思是这样写的:
int res = tmp * (a + b); 如果从命令行进行编译,则编译器可能找不到符号还有另一个原因。您可能只是忘了编译或重新编译其他类。例如,如果您有类,Foo并且Bar在哪里Foo使用Bar。如果您从未编译过Bar并且运行过javac Foo.java,您很有可能发现编译器找不到该符号Bar。简单的答案是编译Foo和Bar在一起; 例如javac Foo.java Bar.java或javac *.java。或者最好还是使用Java构建工具;例如Ant,Maven,Gradle等。
还有一些其他更晦涩的原因...我将在下面处理。
3.如何解决这些错误? 一般来说,首先要弄清楚是什么导致了编译错误。
查看编译错误消息指示的文件中的行。 确定错误消息正在谈论的符号。 弄清楚编译器为什么说找不到符号;为什么?往上看! 然后,您考虑一下您的代码应该说什么。然后,最后您确定需要对源代码进行哪些更正以执行所需的操作。
请注意,并非每个“更正”都是正确的。考虑一下:
for (int i = 1; i < 10; i++) { for (j = 1; j < 10; j++) { ... } } 假设编译器为表示“找不到符号” j。我可以通过多种方式“修复”该问题:
我可以将内部更改for为for (int j = 1; j < 10; j++)-可能是正确的。 我可以在内部循环或外部循环j 之前添加一个声明-可能正确。forfor 我可以更改j为i内for循环-可能是错误的! 等等。 关键是您需要了解您的代码正在尝试做什么才能找到正确的修复程序。
4.原因不明 在一些情况下,“找不到符号”似乎无法解释……直到您仔细观察。
不正确的依赖关系:如果您使用的是IDE或管理构建路径和项目依赖关系的构建工具,则可能是错误的依赖关系;例如遗漏了一个依赖项,或者选择了错误的版本。如果您使用的是构建工具(Ant,Maven,Gradle等),请检查项目的构建文件。如果使用的是IDE,请检查项目的构建路径配置。
您无需重新编译:有时候,新Java程序员可能不了解Java工具链的工作方式,或者没有实现可重复的“构建过程”;例如使用IDE,Ant,Maven,Gradle等。在这种情况下,程序员最终可能会追尾寻找一个虚幻的错误,该错误实际上是由于未正确地重新编译代码而导致的,等等。
较早的构建问题:较早的构建可能会失败,从而导致JAR文件缺少类。如果使用构建工具,通常会注意到这种故障。但是,如果要从其他人那里获取JAR文件,则取决于它们是否可以正确构建并注意到错误。如果您怀疑这一点,请使用tar -tvf列出可疑JAR文件的内容。
IDE问题:人们报告说,他们的IDE感到困惑,并且IDE中的编译器找不到存在的类……或相反的情况。
如果IDE配置了错误的JDK版本,则可能会发生这种情况。
如果IDE的缓存与文件系统不同步,则可能发生这种情况。有特定于IDE的方法可以解决此问题。
这可能是一个IDE错误。例如,@ Joel Costigliola描述了Eclipse无法正确处理Maven“测试”树的情况:请参见此答案。
Android问题:在为Android编程时,您遇到与相关的“找不到符号”错误R,请注意,R符号是由context.xml文件定义的。检查您的context.xml文件正确且正确的位置,以及相应的R类文件是否已生成/编译。请注意,Java符号区分大小写,因此相应的XML ID也区分大小写。
Android上的其他符号错误可能是由于前面提到的原因引起的;例如,缺少或不正确的依赖项,不正确的软件包名称,特定API版本中不存在的方法或字段,拼写/键入错误等。
重新定义系统类:我看到过这样的情况,编译器substring在以下情况中抱怨说这是一个未知符号
String s = ... String s1 = s.substring(1); 事实证明,程序员创建了自己的版本,String而他的类版本未定义substring方法。
课程:不要用与通用库类相同的名称定义自己的类!
象形文字: 如果对源文件使用UTF-8编码,则可能具有看起来相同但实际上不同的标识符,因为它们包含同形文字。有关更多信息,请参见此页面。
通过将自己限制为ASCII或Latin-1作为源文件编码,并对\uxxxx其他字符使用Java 转义,可以避免这种情况。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。