关于Java:”找不到符号”Cannot find symbol编译错误意味着什么?

What does a “Cannot find symbol” compilation error mean?

请解释以下"找不到符号"错误:

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

这个问题被设计成一个关于Java中"找不到符号"编译错误的综合问题。


1。"找不到符号"错误是什么意思?

首先,它是一个编译错误1。这意味着Java源代码中存在问题,或者编译过程中存在问题。好的。

您的Java源代码包括以下内容:好的。

  • 关键词:如truefalseclasswhile等。
  • 文字:如42'X'"Hi mum!"
  • 运算符和其他非字母数字标记:如+={等。
  • 标识符:如ReaderitoStringprocessEquibalancedElephants等。
  • 注释和空白。

"找不到符号"错误是关于标识符的。编译代码时,编译器需要计算出代码中每个标识符的含义。好的。

"找不到符号"错误表示编译器无法执行此操作。您的代码似乎引用了编译器无法理解的内容。好的。2。什么会导致"找不到符号"错误?

作为一级命令,只有一个原因。编译器查找了所有应该定义标识符的地方,但找不到定义。这可能是由一些事情引起的。常见的有:好的。

  • 对于一般标识符:
    • 也许你把名字拼错了,即用StringBiulder代替StringBuilder。Java不能也不会试图补偿拼写错误或键入错误。
    • 也许你搞错了,也就是说,用StringBuilder代替StringBuilder。所有Java标识符都区分大小写。
    • 也许您不恰当地使用下划线;例如,mystringmy_string是不同的。(如果你坚持Java风格的规则,你将在很大程度上避免这种错误……)
    • 也许您正试图使用声明为"其他地方"的内容;即,在另一个上下文中,您隐式地告诉编译器要查看的内容。(不同的班级?不同的范围?一个不同的包裹?不同的代码库?)
  • 对于应引用变量的标识符:
    • 也许你忘了声明变量。
    • 在您试图使用变量声明时,它可能超出了范围。(见下例)
  • 对于应该是方法名或字段名的标识符:
    • 可能您正试图引用一个继承的方法或字段,而该方法或字段没有在父类/祖先类或接口中声明。
    • 可能您试图引用的方法或字段在您使用的类型中不存在(即尚未声明);例如,"someString".push()2。
    • 也许您试图将方法用作字段,或者相反;例如,"someString".lengthsomeArray.length()
  • 对于应为类名的标识符:好的。

    • 也许你忘了导入类。
    • 也许您使用了"star"导入,但是类没有在您导入的任何包中定义。
    • 也许你忘记了一个new,比如:好的。

      1
      String s = String();  // should be 'new String()'
  • 对于类型或实例似乎没有预期的成员的情况:好的。

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

问题往往是上述两者的结合。例如,也许你"星"进口了java.io.*,然后尝试使用Files类……在java.nio中,而不是java.io中。或者你是想写一本书。它是java.io中的一个类。好的。

下面是一个示例,说明不正确的变量范围会导致"找不到符号"错误:好的。

1
2
3
4
5
6
7
8
for (int i = 0; i < strings.size(); i++) {
    if (strings.get(i).equalsIgnoreCase("fnoord")) {
        break;
    }
}
if (i < strings.size()) {
    ...
}

这将给if语句中的i带来"找不到符号"错误。虽然我们以前声明过i,但该声明仅适用于for声明及其正文。if号声明中提及的i不能看到i号声明。超出范围。好的。

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

下面是一个导致困惑的例子,打字错误导致了一个看似无法解释的"找不到符号"错误:好的。

1
2
3
for (int i = 0; i < 100; i++); {
    System.out.println("i is" + i);
}

这会在println调用中给您一个编译错误,说明找不到i。但(我听到你说)我确实宣布了!好的。

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

1
2
3
4
5
6
7
for (int i = 0; i < 100; i++);

// The previous and following are separate statements!!

{
    System.out.println("i is" + i);
}

{ ... }块不是for循环的主体,因此for语句中以前的i声明超出了该块的范围。好的。

这里是另一个由打字错误引起的"找不到符号"错误的例子。好的。

1
2
int tmp = ...
int res = tmp(a + b);

尽管之前有声明,但tmp(...)表达式中的tmp是错误的。编译器将查找名为tmp的方法,但找不到。前面声明的tmp位于变量的命名空间中,而不是方法的命名空间。好的。

在我遇到的例子中,程序员实际上漏掉了一个操作员。他想写的是:好的。

1
int res = tmp * (a + b);

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

还有其他一些更为隐晦的原因…我将在下面处理。好的。三。如何修复这些错误?

一般来说,首先要弄清楚是什么导致了编译错误。好的。

  • 查看编译错误消息指示的文件中的行。
  • 确定错误消息所指的符号。
  • 找出编译器为什么说找不到符号;请参见上面的内容!

然后你想想你的代码应该说什么。最后,您需要对源代码进行什么样的修正,才能完成您想要的工作。好的。

请注意,并非每个"更正"都是正确的。考虑一下:好的。

1
2
3
4
5
for (int i = 1; i < 10; i++) {
    for (j = 1; j < 10; j++) {
        ...
    }
}

假设编译器对j说"找不到符号"。我有很多方法可以"修复"它:好的。

  • 我可以把里面的for改成for (int j = 1; j < 10; j++),也许是对的。
  • 我可以在内部for循环或外部for循环之前为j添加声明-可能是正确的。
  • 我可以把j改为i,在内部的for循环中-可能是错的!
  • 等等。

要点是,您需要了解代码试图做什么,以便找到正确的修复方法。好的。4。模糊原因

这里有两种情况,"找不到符号"似乎难以解释…直到你看得更近。好的。

  • 不正确的依赖项:如果使用的是管理生成路径和项目依赖项的IDE或生成工具,则可能对依赖项犯了错误;例如,遗漏了依赖项或选择了错误的版本。如果您使用的是构建工具(Ant、Maven、Gradle等),请检查项目的构建文件。如果使用的是IDE,请检查项目的构建路径配置。好的。

  • 您没有重新编译:有时新Java程序员不理解Java工具链是如何工作的,或者没有实现可重复的"构建过程";例如使用IDE、ANT、Maven、Gradle等。在这种情况下,程序员最终可能会追寻自己的尾巴,寻找一个实际上是由于没有正确地重新编译代码而导致的错误,等等……好的。

  • 早期版本的问题:它是可能的,早期的失败是生成在一个JAR文件单给A一班。搜索设备失效会注意到如果你是使用一个版本的工具。但是如果你从别人得到的JAR文件,你在他们的建筑,没有依赖性,和noticing错误。如果你看看这个列表的内容,使用tar -tvfof the suspect的JAR文件。

  • IDE的问题:有人会在他们的案例被混淆的IDE和编译器在IDE无法找到一个一流的存在……或反向的情况。

    • 这可以发生,如果IDE’s get走出同步缓存文件系统。有特异的方式来固定这是IDE。

    • 这可能是在IDE的bug。例如:"在目前情况costigliola乔尔Eclipse不手柄a Maven的"测试"这个正确答案:湖树。

  • redefining系统类:我的湖泊。在编译substring投诉,是未知的,什么样的图标

    1
    2
    String s = ...
    String s1 = s.substring(1);

    它使程序员创造出这样一个自己的版本的版本,他的String这类不substringdefine a的方法。

    教训:不要使用你自己的类相同的名称作为一个类的公共图书馆。

  • homoglyphs:如果你使用UTF-8编码的源文件,它是可能的,有标识看起来一样,但实际上他们是不同的,因为homoglyphs包含。湖本页的更多信息。

    你可以通过自己来避免这restricting ASCII或为Latin-1编码使用Java源文件,和其他\uxxxx转义字符。

  • 1如果你perchance湖,这一运行时异常或错误消息,那么你已经配置您的IDE运行代码和编译错误,或是生成和编译代码的应用程序。在运行时。

    2土木工程的基本原则三:水不流完成,A板是在其侧更强,你不能推一弦。

    好的。


    如果您忘记了new,也会得到这个错误:

    1
    String s = String();

    对战

    1
    String s = new String();


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

    正如我已经看到过几次这样的问题,也许还有一个例子可以说明什么是非法的,即使它可能感觉良好。

    考虑此代码:

    1
    2
    3
    4
    5
    6
    if(somethingIsTrue()) {
      String message ="Everything is fine";
    } else {
      String message ="We have an error";
    }
    System.out.println(message);

    这是无效代码。因为两个名为message的变量都不在各自的作用域之外可见,在本例中,这两个变量都是包围括号{}

    您可能会说:"但是名为message的变量是以任何方式定义的,因此message是在if之后定义的。"

    但你错了。

    Java没有EDCOX1,4或EDCOX1,5个操作符,因此必须依靠跟踪变量范围来发现变量何时不再被使用(连同这些变量的原因的引用)。

    如果你认为你做了好事,那就更糟了。我在这样的"优化"代码之后看到了这种错误:

    1
    2
    3
    4
    5
    6
    7
    if(somethingIsTrue()) {
      String message ="Everything is fine";
      System.out.println(message);
    } else {
      String message ="We have an error";
      System.out.println(message);
    }

    "哦,这里有重复的代码,让我们把这条公用线拉出来"->然后就到了。

    处理此类范围问题的最常见方法是将else值预先分配给外部范围中的变量名,然后在if:

    1
    2
    3
    4
    5
    String message ="We have an error";
    if(somethingIsTrue()) {
      message ="Everything is fine";
    }
    System.out.println(message);


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

  • src/test/java中定义一个类A
  • src/main/java中定义另一个使用A类的类B
  • 结果:Eclipse将编译代码,但Maven将给出"找不到符号"。

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

    解决方案:

  • 不要这样定义你的依赖关系;也就是说,不要犯这个错误。
  • 定期使用Maven构建代码库,以便尽早发现这个错误。一种方法是使用CI服务器。

  • "找不到"是指编译器找不到合适的变量、方法、类等。如果你得到了错误消息,首先你要找到代码行,在那里得到错误消息。然后你就可以在使用之前找到没有定义的变量、方法或类。确认后,初始化该变量、方法或类。可用于以后的需求…请考虑以下示例。

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

    1
    2
    3
    4
    5
    class demo{
          public static void main(String a[]){
                 System.out.print(name);
          }
    }

    现在看看结果……

    enter image description here

    该错误表示,"变量名找不到"…定义和初始化"名称"变量的值可以取消该错误..实际上是这样的,

    1
    2
    3
    4
    5
    6
    7
    8
    class demo{
          public static void main(String a[]){

                 String name="smith";

                 System.out.print(name);
          }
    }

    现在看看新的输出…

    enter image description here

    OK成功地解决了这个错误..同时,如果你能得到"找不到方法"或"找不到类"的东西,首先定义一个类或方法,然后使用它..


    如果你在其他地方构建了这个错误,而你的IDE说一切都很好,那么检查你在两个地方使用的是相同的Java版本。

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


    如果Eclipse Java构建路径被映射到7, 8,并且在Projo POM.XML Maven属性java.版本中提到了更高的Java版本(9,10,11,等等),而不是7,8,则需要在POM.XML文件中进行更新。

    在Eclipse中,如果Java映射到Java版本11和POM.XML,则映射到Java版本8。通过Eclipse IDE中的以下步骤更新Eclipse对Java 11的支持帮助->安装新软件->

    粘贴以下链接http://download.eclipse.org/eclipse/updates/4.9-p-builds-at-work-with

    添加(弹出窗口将打开)->

    EDCOX1·2·Java 11支持Location:http://download.eclipse.org/eclipse/updates/4.9-p-builds

    然后在POM.XML文件的Maven属性中更新Java版本,如下所示

    1
    2
    3
    <java.version>11</java.version>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>

    最后右键单击项目调试as->maven clean,maven build steps


    正如上面提到的,可能会有各种各样的场景。一些帮助我解决这个问题的事情。

  • 如果您使用Intellij

    File -> 'Invalidate Caches/Restart'

  • 被引用的类在另一个项目中,并且该依赖项没有添加到我的项目的Gradle构建文件中。所以我用

    compile project(':anotherProject')

  • 它奏效了。嗯!


    有关提示,请仔细查看引发错误的类名和行号,例如:编译失败[错误] 应用程序xxxxx .java:[44,30]错误:找不到符号

    另一个原因是不支持Java版本的方法,如JDK7 vs 8。检查您的%java_主页%


    我也收到了这个错误。(我在谷歌上搜索了一下,然后就被转到了这一页)

    问题:我正在从另一个项目B中定义的类调用项目A类中定义的静态方法。我收到以下错误:

    1
    error: cannot find symbol

    解决方案:我通过首先在定义方法的项目中构建方法,然后从中调用方法的项目来解决这个问题。