Что означает ошибка компиляции "не удается найти символ"?

пожалуйста, объясните следующее об ошибке" не удается найти символ":

  • что означает эта ошибка означает?
  • какие вещи могут вызвать эту ошибку?
  • как программист собирается исправить эту ошибку?

этот вопрос предназначен для всестороннего вопроса об ошибках компиляции "не удается найти символ" в Java.

10 ответов


1. Что означает ошибка "не удается найти символ"?

во-первых, это ошибка компиляции1. Это значит, что или существует проблема в исходном коде Java,или существует проблема в том, как вы его компилируете.

исходный код Java состоит из следующих вещей:

  • ключевые слова: like true, false, class, while и так на.
  • литералы: как 42 и 'X' и "Hi mum!".
  • операторы и другие не буквенно-цифровые маркеры: как +, =, { и так далее.
  • идентификаторы: как Reader, i, toString, processEquibalancedElephants и так далее.
  • комментарии и пробелы.

ошибка "не удается найти символ" касается идентификаторов. Когда ваш код компилируется, компилятор должен выяснить, что каждый идентификатор в вашем коде означает.

ошибка "не удается найти символ" означает, что компилятор не может этого сделать. Ваш код указывает на то, что компилятор не понимает.

2. Что может вызвать ошибку" не удается найти символ"?

в первую очередь, существует только одна причина. Компилятор искал во всех местах, где идентификатор должны быть определенным, и он не смог найти определение. Это может быть вызвано рядом вещи. Общие из них следующие:

  • для идентификаторов в целом:
    • возможно, вы неправильно написали имя; то есть StringBiulder вместо StringBuilder. Java не может и не будет пытаться компенсировать ошибки орфографии или ввода.
    • возможно, вы неправильно поняли дело; т. е. stringBuilder вместо StringBuilder. Все идентификаторы Java чувствительны к регистру.
    • возможно, вы использовали подчеркивания неуместно; то есть mystring и my_string разные. (Если вы придерживаетесь правил стиля Java, вы будете в значительной степени защищены от этой ошибки ...)
    • возможно, вы пытаетесь использовать что-то, что было объявлено "где-то еще"; т. е. в другом контексте, где вы неявно сказали компилятору искать. (Другой класс? Другой масштаб? Другой пакет? Другая кодовая база?)
  • для идентификаторов, которые должны ссылаться на переменные:
    • возможно вы забыли объявить переменную.
    • возможно, объявление переменной выходит за рамки в момент, когда вы пытались его использовать. (См. пример ниже)
  • для идентификаторов, которые должны быть именами методов или полей:
    • возможно, вы пытаетесь сослаться на унаследованный метод или поле, которое не было объявлено в родительских / предковых классах или интерфейсах.
    • вы пытаетесь использовать метод в качестве поля, или наоборот; например, "someString".length или someArray.length().
  • для идентификаторов, которые должны быть имена классов:

    • возможно, вы забыли импортировать класс.
    • возможно, вы использовали импорт "star", но класс не определен ни в одном из пакетов, которые вы импортировали.
    • возможно, вы забыли a new в:

      String s = String();  // should be 'new String()'
      
  • для случаев, когда тип или экземпляр, как представляется, не имеют член, который вы ожидали, что он будет иметь:

    • возможно, вы объявили вложенный класс или общий параметр, который тени тип, который вы собирались использовать.
    • возможно, вы затеняете статическую переменную или переменную экземпляра.
    • возможно, вы импортировали неправильный тип; например, из-за завершения IDE или автоматической коррекции.
    • возможно, вы используете (компилируете) неправильную версию API.
    • возможно, вы забыл перевести объект в соответствующий подкласс.
  • проблема часто комбинация выше. Например, может быть, вы" звезда " импортировали java.io.* а затем попытался использовать Files класса ... который находится в java.nio не java.io. Или, может быть, вы хотели написать File ... который is класс java.io.


    вот пример того, как неправильная область видимости переменных может привести к " не удается найти символ" ошибка:

    for (int i = 0; i < strings.size(); i++) {
        if (strings.get(i).equalsIgnoreCase("fnoord")) {
            break;
        }
    }
    if (i < strings.size()) {
        ...
    }
    

    это даст ошибку "не удается найти символ" для i на if заявление. Хотя мы ранее заявляли i, это заявление только в область на for заявление и его тело. Ссылка на i на if сообщении не вижу что декларация i. Это выходит за рамки.

    (соответствующей коррекцией здесь может быть перемещение if оператор внутри цикла, или объявить i перед началом цикла.)


    вот пример, который вызывает недоумение, когда опечатка приводит к кажущейся необъяснимой ошибке "не может найти символ":

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

    это даст вам ошибку компиляции в println позвонили и сказали, что i не удается найти. Но (я слышу, как вы говорите)я объявил это!

    проблема подлый запятой перед {. язык Java определяет, что это пустые заявления. Так что этот код на самом деле означает следующее:

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

    The { ... } блок не является телом for цикл, поэтому объявление i не в область в блоке.


    вот еще один пример ошибки "не удается найти символ", вызванной опечаткой.

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

    несмотря на предыдущее заявление,tmp на tmp(...) выражение является ошибочным. Этот компилятор будет искать метод под названием tmp и не найдешь. Ранее объявленное tmp находится в пространстве имен для переменных, а не в пространстве имен для методов.

    в Примере, с которым я столкнулся, программист фактически опустил оператор. Вот что он хотел написать:--92-->

    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 до внутренний for петля, или внешняя for петли - возможно, правильно.
    • я мог бы измениться j to 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 "test" правильно:посмотреть этот ответ.

    5. переопределение системных классов: я видел случаи, когда компилятор жалуется, что substring является неизвестным символом в чем-то вроде следующего

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

      оказалось, что программист создал собственную версию String и что его версия класса не определить substring методы.

      урок: не определяйте свои собственные классы с теми же именами, что и обычные классы библиотеки!

    6. Homoglyphs: если вы используете кодировку UTF-8 для своих исходных файлов, возможно иметь идентификаторы, которые посмотреть то же, но на самом деле это разные, потому что они содержат homoglyphs. См.на этой странице для получения дополнительной информации.

      вы можете избежать этого, ограничив себя ASCII или Latin-1 в качестве кодировки исходного файла и используя Java \uxxxx escapes для других символов.


    1-Если, возможно, вы do см. это в исключении или сообщении об ошибке среды выполнения, затем либо вы настроили IDE для запуска кода с ошибками компиляции, либо ваше приложение генерирует и компилирует код .. во время выполнения.


    вы также получите эту ошибку, если вы забыли new:

    String s = String();
    

    и

    String s = new String();
    

    еще один пример "Variable is out of scope"

    как я уже видел такие вопросы несколько раз, может быть, еще один пример того, что незаконно, даже если это может чувствовать ОК.

    рассмотрим этот код:

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

    это неверный код. Потому что ни одна из переменных с именем message виден за пределами их соответствующей области-которая будет заключена в окружающие скобки {} в этом случае.

    вы можете сказать: "но переменная с именем message определяется в любом случае-so message is определена после 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);
    }
    

    "о, есть дублированный код, давайте вытащим эту общую линию" - > и там это.

    наиболее распространенным способом решения такого рода проблем с областью было бы предварительно назначить значения else именам переменных во внешней области, а затем переназначить, если:

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

    один из способов получить эту ошибку в Eclipse:

    1. определить класс A на src/test/java.
    2. определить другой класс B на src/main/java который использует class A.

    результат: Eclipse скомпилирует код, но maven даст "не удается найти символ".

    основная причина: Eclipse использует комбинированный путь сборки для основного и тестового деревьев. К сожалению, он не поддерживает использование разных путей сборки для разных частей Проект Eclipse, который требуется Maven.

    устранение :

    1. не определяйте свои зависимости таким образом; т. е. не делайте этой ошибки.
    2. регулярно создавайте свою кодовую базу с помощью Maven, чтобы вы рано поняли эту ошибку. Один из способов сделать это-использовать сервер CI.

    Если вы получаете эту ошибку в сборке где-то еще, в то время как ваша IDE говорит, что все в порядке, тогда проверьте, что вы используете одни и те же версии Java в обоих местах.

    например, Java 7 и Java 8 имеют разные API, поэтому вызов несуществующего API в более старой версии Java вызовет эту ошибку.


    "Не могу найти" означает , что компилятор, который не может найти соответствующую переменную, метод, класс и т. д...если вы получили этот массаж ошибок, прежде всего, вы хотите найти строку кода, где получить массаж ошибок..И тогда вы сможете найти , какую переменную, метод или класс не определили перед ее использованием.После подтверждения инициализируйте эту переменную, метод или класс можно использовать для последующего require...Рассмотрим следующий пример.

    Я создам демонстрационный класс и напечатаю имя...

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

    теперь посмотрите на результат..

    enter image description here

    что ошибка говорит, "имя переменной не может найти"..Определение и инициализация значения переменной "name" может быть отменена этой ошибкой..На самом деле вот так,

    class demo{ 
          public static void main(String a[]){
    
                 String name="smith";
    
                 System.out.print(name);
          }
    }
    

    теперь посмотрите на новый вывод...

    enter image description here

    Ok успешно решил эту ошибку..в то же время, если вы можете получить "не могу найти метод" или " не могу найти класс " что-то,сначала определите класс или метод и после этого используйте это..


    Я тоже получал эту ошибку. (для которого я погуглил, и я был направлен на эту страницу)

    : я вызывал статический метод, определенный в классе проекта A из класса, определенного в другом проекте B. Я получал следующую ошибку:

    error: cannot find symbol
    

    устранение: я решил это, сначала построив проект, где метод определен, а затем проект, из которого вызывался метод.


    для подсказок, посмотрите ближе на имя класса имя, которое выдает ошибку и номер строки, например: Сбой компиляции [Ошибка] \applications\xxxxx.java: [44,30] ошибка: не удается найти символ

    еще одна причина-неподдерживаемый метод для версии java, скажем jdk7 vs 8. Проверьте %JAVA_HOME%


    могут быть различные сценарии, как люди упомянули выше. Пара вещей, которые помогли мне решить эту проблему.

    1. Если вы используете IntelliJ

      File -> 'Invalidate Caches/Restart'

    или

    1. указанный класс был в другом проекте, и эта зависимость не была добавлена в файл сборки Gradle моего проекта. Поэтому я добавил зависимость используя

      compile project(':anotherProject')

    и это сработало. НТН!


    вы также можете получить эту ошибку, если вы объявляете с неправильным типом, например:

    Boolean вместо boolean

    целое число вместо int

    строку вместо строка