什么是"找不到符号"编译错误是什么意思?

Ste*_*n C 364 java compiler-errors cannot-find-symbol

请解释以下关于"无法找到符号"的错误:

  • 这个错误是什么意思?
  • 什么东西会导致这个错误?
  • 程序员如何解决此错误?

这个问题旨在成为一个关于Java中"无法找到符号"编译错误的综合问题.

Ste*_*n C 381

1."无法找到符号"错误是什么意思?

首先,它是编译错误1.这意味着,无论有在Java源代码中的问题,有在你编译它的方式有问题.

您的Java源代码包含以下内容:

  • 关键词:喜欢true,false,class,while,等.
  • 文字:喜欢42'X'"Hi mum!".
  • 运营商和其他非字母数字标记:像+,=,{,等等.
  • 标识符:喜欢Reader,i,toString,processEquibalancedElephants,等.
  • 评论和空白.

"无法找到符号"错误与标识符有关.编译代码时,编译器需要确定代码中每个标识符的含义.

"无法找到符号"错误意味着编译器无法执行此操作.您的代码似乎是指编译器无法理解的内容.

2.什么可能导致"找不到符号"错误?

作为第一个订单,只有一个原因.编译器查找了应该定义标识符的所有位置,并且找不到定义.这可能是由许多事情引起的.常见的如下:

  • 对于标识符一般:
    • 也许你拼错了名字; 即StringBiulder代替StringBuilder.Java不能也不会尝试补偿错误的拼写或输入错误.
    • 也许你弄错了; 即stringBuilder代替StringBuilder.所有Java标识符都区分大小写.
    • 也许你不恰当地使用了下划线; 即mystringmy_string不同.(如果您坚持使用Java样式规则,那么您将在很大程度上受到这种错误的保护......)
    • 也许你正在尝试使用被宣称为"其他地方"的东西; 即在不同的上下文中,你隐含地告诉编译器.(一个不同的类?一个不同的范围?一个不同的包?一个不同的代码库?)
  • 对于应引用变量的标识符:
    • 也许你忘了申报变量了.
    • 也许变量声明在您尝试使用它时超出范围.(见下面的例子)
  • 对于应该是方法或字段名称的标识符:
    • 也许您正在尝试引用未在父/祖先类或接口中声明的继承方法或字段.
    • 也许您正在尝试引用您正在使用的类型中不存在(即尚未声明)的方法或字段; 例如"someString".push()2.
    • 也许您正在尝试将方法用作字段,反之亦然; 例如"someString".lengthsomeArray.length().
  • 对于应该是类名的标识符:

    • 也许你忘了导入这门课了.
    • 也许您使用了"star"导入,但是在导入的任何包中都没有定义该类.
    • 也许你忘记了new:

      String strings[] = ...
      if (strings.charAt(3)) { ... }
      // maybe that should be 'strings[0].charAt(3)'
      
      Run Code Online (Sandbox Code Playgroud)
  • 对于类型或实例似乎没有您期望的成员的情况:

    • 也许您已经声明了一个嵌套类或泛型参数,它们会影响您要使用的类型.
    • 也许您正在隐藏静态或实例变量.
    • 也许你导入了错误的类型; 例如,由于IDE完成或自动更正.
    • 也许您正在使用(编译)错误版本的API.
    • 也许您忘了将对象转换为适当的子类.

问题通常是上述的组合.例如,也许你"明星"导入java.io.*,然后尝试使用Files该类...这java.nio不是java.io.或许你打算写File...这一个班级java.io.


以下是不正确的变量范围如何导致"无法找到符号"错误的示例:

String s = String();  // should be 'new String()'
Run Code Online (Sandbox Code Playgroud)

这将iif语句中给出"无法找到符号"错误.虽然我们之前已经声明i,但该声明仅适用for声明及其正文.以参考iif声明中无法看到的那个声明i.它超出了范围.

(这里适当的修正可能是if在循环中移动语句,或者i在循环开始之前声明.)


这是一个导致困惑的例子,其中拼写错误导致看似莫名其妙的"无法找到符号"错误:

List<String> strings = ...

for (int i = 0; i < strings.size(); i++) {
    if (strings.get(i).equalsIgnoreCase("fnord")) {
        break;
    }
}
if (i < strings.size()) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

这将在println调用中显示i无法找到的编译错误.但是(我听你说)我确实宣布了!

问题是之前的鬼鬼祟祟的分号(;){.Java语言语法将该上下文中的分号定义为空语句.然后空语句成为for循环体.所以代码实际上意味着:

for (int i = 0; i < 100; i++); {
    System.out.println("i is " + i);
}
Run Code Online (Sandbox Code Playgroud)

{ ... }块不是身体for循环,并因此与先前的声明i中的for说法是超出范围的块.


这是由拼写错误引起的"无法找到符号"错误的另一个示例.

for (int i = 0; i < 100; i++); 

// The previous and following are separate statements!!

{
    System.out.println("i is " + i);
}
Run Code Online (Sandbox Code Playgroud)

尽管与先前的声明中,tmptmp(...)表达是错误的.编译器将查找一个名为的方法tmp,但不会找到一个方法.先前声明的tmp是变量的名称空间,而不是方法的名称空间.

在我遇到的例子中,程序员实际上已经遗漏了一个操作员.他打算写的是:

int tmp = ...
int res = tmp(a + b);
Run Code Online (Sandbox Code Playgroud)

如果从命令行编译,编译器可能找不到符号还有另一个原因.您可能只是忘记编译或重新编译其他类.举例来说,如果你有类FooBar地方Foo使用Bar.如果您从未编译过Bar并且运行过javac Foo.java,则可能会发现编译器无法找到该符号Bar.简单的答案是编译FooBar在一起; 例如javac Foo.java Bar.javajavac *.java.或者更好的是仍然使用Java构建工具; 例如Ant,Maven,Gradle等.

还有其他一些比较模糊的原因......我将在下面讨论.

3.如何修复这些错误?

一般来说,您首先要弄清楚导致编译错误的原因.

  • 查看编译错误消息指示的文件中的行.
  • 确定错误消息正在讨论的符号.
  • 弄清楚为什么编译器说它无法找到符号; 往上看!

然后你想想你的代码应该说些什么.最后,您需要确定需要对源代码进行哪些更正才能执行您想要的操作.

请注意,并非每个"校正"都是正确的.考虑一下:

int res = tmp * (a + b);
Run Code Online (Sandbox Code Playgroud)

假设编译器说"找不到符号" j.有很多方法可以"修复":

  • 我可以改变内forfor (int j = 1; j < 10; j++)-可能是正确的.
  • 我可以在内循环或外循环j 之前添加一个声明- 可能是正确的.forfor
  • 我可以改变j,以i在内部for循环-可能是错的!
  • 等等.

关键是您需要了解代码尝试执行的操作才能找到正确的修复方法.

4.模糊的原因

这里有几个案例,"无法找到符号"看起来似乎莫名其妙......直到你仔细观察.

  1. 不正确的依赖项:如果您使用的是IDE或构建工具来管理构建路径和项目依赖项,那么您可能在依赖项方面犯了错误; 例如,遗漏了依赖关系,或选择了错误的版本.如果您使用的是构建工具(Ant,Maven,Gradle等),请检查项目的构建文件.如果您使用的是IDE,请检查项目的构建路径配置.

  2. 您没有重新编译:有时会发生新的Java程序员不了解Java工具链的工作原理,或者没有实现可重复的"构建过程"; 例如使用IDE,Ant,Maven,Gradle等.在这种情况下,程序员最终可能会追逐他的尾巴寻找一个虚幻的错误,这个错误实际上是由于没有正确地重新编译代码而导致的......等等......

  3. 较早的构建问题:早期构建可能以一种给JAR文件缺少类的方式失败.如果您使用构建工具,通常会注意到这种失败.但是,如果您从其他人那里获取JAR文件,则依赖于它们正确构建并注意错误.如果您怀疑这一点,请使用tar -tvf列出可疑JAR文件的内容.

  4. IDE问题:人们已经报告了他们的IDE混淆的情况,并且IDE中的编译器找不到存在的类......或者相反的情况.

    • 如果IDE的缓存与文件系统不同步,则会发生这种情况.有IDE特定的方法来解决这个问题.

    • 这可能是一个IDE错误.例如,@ Joel Costigliola描述了Eclipse无法正确处理Maven"测试"树的场景:请参阅此答案.

  5. 重新定义系统类:我已经看到了编译器抱怨这R是一个未知符号的情况,如下所示

    for (int i = 1; i < 10; i++) {
        for (j = 1; j < 10; j++) {
            ...
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    事实证明,程序员已经创建了自己的版本,R并且他的类版本没有定义context.xml方法.

    课程:不要使用与公共库类相同的名称来定义自己的类!

  6. Homoglyphs: 如果对源文件使用UTF-8编码,则可能具有看起来相同但实际上不同的标识符,因为它们包含同形字符.有关更多信息,请参阅此页面.

    您可以通过将自己限制为ASCII或Latin-1作为源文件编码,并将Java context.xml转义符用于其他字符来避免这种情况.


1 -如果,或许,你看到这个运行时异常或错误信息,那么无论你已经配置了IDE运行具有编译错误的代码,或者您的应用程序生成和编译代码..在运行时.

2 - 土木工程的三个基本原则:水不会上坡,木板侧面更强,你不能用绳子推.


thi*_*rry 22

如果您忘记了new以下情况,您也会收到此错误:

String s = String();
Run Code Online (Sandbox Code Playgroud)

String s = new String();
Run Code Online (Sandbox Code Playgroud)

  • 经过大约一个小时的扫描代码后,我找到了这个答案 - 感谢上帝! (2认同)

Jan*_*Jan 14

"变量超出范围"的另一个例子

正如我已经看过几次这样的问题,也许还有一个例子,即使它可能感觉不错也是非法的.

考虑以下代码:

if(somethingIsTrue()) {
  String message = "Everything is fine";
} else {
  String message = "We have an error";
}
System.out.println(message);
Run Code Online (Sandbox Code Playgroud)

这是无效的代码.因为命名的变量都不在message其各自的范围之外可见 - {}在这种情况下,这将是周围的括号.

你可能会说:"但是,一个名为消息变量定义两种方式-这样的消息后定义if".

但你错了.

Java没有free()delete运算符,所以它必须依赖跟踪变量范围来找出何时不再使用变量(以及对这些原因变量的引用).

如果你认为你做了一件好事,那就特别糟糕了.在"优化"代码之后我看到了这种错误:

if(somethingIsTrue()) {
  String message = "Everything is fine";
  System.out.println(message);
} else {
  String message = "We have an error";
  System.out.println(message);
}
Run Code Online (Sandbox Code Playgroud)

"哦,有重复的代码,让我们拉出那条普通的线路" - >然后就可以了.

处理这种范围问题的最常见方法是将else-values预先分配给外部作用域中的变量名称,然后在以下情况下重新分配:

String message = "We have an error";
if(somethingIsTrue()) {
  message = "Everything is fine";
} 
System.out.println(message);
Run Code Online (Sandbox Code Playgroud)

  • *"Java没有free()或delete运算符,因此它必须依赖跟踪变量作用域来找出何时不再使用变量(以及对这些原因变量的引用)."* - 虽然为true,但这不相关.C和C++分别有free/delete操作符,但是你的例子的等效C/C++代码是非法的.C和C++块限制变量的范围,就像在Java中一样.事实上,大多数"块结构化"语言都是如此. (4认同)

Joe*_*ola 9

在Eclipse中获取此错误的一种方法:

  1. 定义一个类Asrc/test/java.
  2. Bsrc/main/java该使用类中定义另一个类A.

结果:Eclipse将编译代码,但maven将给出"找不到符号".

基本原因:Eclipse正在使用主树和测试树的组合构建路径.不幸的是,它不支持为Eclipse项目的不同部分使用不同的构建路径,这是Maven所需要的.

方案:

  1. 不要那样定义依赖关系; 即不要犯这个错误.
  2. 定期使用Maven构建代码库,以便尽早发现这个错误.一种方法是使用CI服务器.

  • 无论你的src/main/java的使用需要的src/main/java或任何编译/运行时依赖(未测试依赖)来定义. (2认同)

小智 8

解决了

使用 IntelliJ

选择Build -> Rebuild Project 即可解决

  • 这很大程度上取决于情况,但通常情况下并非如此。 (3认同)

Jon*_*Lin 5

如果您在其他地方的构建中遇到此错误,而您的 IDE 表示一切正常,那么请检查您在两个地方是否使用相同的 Java 版本。

例如,Java 7 和 Java 8 有不同的 API,因此在较旧的 Java 版本中调用不存在的 API 会导致此错误。


GT_*_*ash 5

“找不到”表示编译器找不到合适的变量,方法,类等...如果您得到了错误提示,首先您要查找得到错误提示的代码行。然后,您将找到能够在使用之前找到尚未定义的变量,方法或类。确认初始化后,该变量,方法或类可用于以后的需求...请考虑以下示例。

我将创建一个演示类并打印名称...

class demo{ 
      public static void main(String a[]){
             System.out.print(name);
      }
}
Run Code Online (Sandbox Code Playgroud)

现在看一下结果。

在此处输入图片说明

该错误表示“找不到变量名”。可以消除“ name”变量的定义和初始化值。实际上,

class demo{ 
      public static void main(String a[]){

             String name="smith";

             System.out.print(name);
      }
}
Run Code Online (Sandbox Code Playgroud)

现在看看新的输出...

在此处输入图片说明

好,成功解决了该错误。同时,如果您得到“找不到方法”或“找不到类”的东西,请首先定义一个类或方法,然后再使用它。


avp*_*avp 5

正如人们在之前的答案中提到的那样,可能存在各种情况。以下是帮助我解决此问题的几件事。

\n
    \n
  1. 如果您使用的是IntelliJ IDEA

    \n

    菜单文件\xe2\x86\x92使缓存无效/重新启动

    \n
  2. \n
\n

或者

\n
    \n
  1. 被引用的类位于另一个项目中,并且该依赖项未添加到我的项目的 Gradle 构建文件中。所以我使用添加了依赖项

    \n

    compile project(\':anotherProject\')

    \n

    它奏效了。

    \n
  2. \n
\n