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

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

  • Что означает эта ошибка?
  • Что может привести к этой ошибке?
  • Как программист исправляет эту ошибку?

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

Ответ 1

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

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

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

  • Ключевые слова: например, true, false, class, while и т.д.
  • Литералы: как 42 и 'X' и "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.
    • Возможно, вы забыли привести свой объект к соответствующему подклассу.

Проблема часто заключается в сочетании вышеперечисленного. Например, может быть, вы "звездой" импортировали 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()) {
    ...
}

Это приведет к ошибке "Не удается найти символ" для 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. Так что этот код на самом деле означает это:

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; например Муравей, мавен, Градл и т.д.

Есть и другие неясные причины, о которых я расскажу ниже.

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 на 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 была настроена с неверной версией JDK.

    • Это может произойти, если кэши IDE не синхронизируются с файловой системой. Есть конкретные способы исправить это в среде IDE.

    • Это может быть ошибка IDE. Например, @Joel Costigliola описывает сценарий, в котором Eclipse неправильно обрабатывает "тестовое" дерево Maven: см. Этот ответ.

  5. Проблемы с Android: если вы программируете для Android и у вас есть ошибки "Не удается найти символ", связанные с R, имейте в виду, что символы R определены в файле context.xml. Убедитесь, что ваш файл context.xml правильный и в правильном месте, и что соответствующий файл класса R был сгенерирован/скомпилирован. Обратите внимание, что символы Java чувствительны к регистру, поэтому соответствующие идентификаторы XML также чувствительны к регистру.

    Другие ошибки символов в Android, скорее всего, связаны с ранее упомянутыми причинами; например отсутствующие или неверные зависимости, неправильные имена пакетов, методы или поля, которых нет в определенной версии API, ошибки правописания/ввода и т.д.

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

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

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

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

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

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


1 - If, perchance, you do see this in a runtime exception or error message, then either you have configured your IDE to run code with compilation errors, or your application is generating and compiling code .. at runtime.

2 - The three basic principles of Civil Engineering: water does not flow uphill, a plank is stronger on its side, and you can't push on a string.

Ответ 2

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

String s = String();

против

String s = new String();

потому что вызов без ключевого слова new попытается найти (локальный) метод с именем String без аргументов - и подпись этого метода, вероятно, не определена.

Ответ 3

Еще один пример "Переменная выходит за рамки"

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

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

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

Этот недопустимый код. Потому что ни одна из переменных с именем 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);
}

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

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

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

Ответ 4

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

  • Определите класс A в src/test/java.
  • Определите другой класс B в src/main/java, который использует класс A.

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

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

Решение:

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

Ответ 5

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

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

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

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

enter image description here

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

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

             String name="smith";

             System.out.print(name);
      }
}

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

enter image description here

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

Ответ 6

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

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

Ответ 7

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

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

error: cannot find symbol

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

Ответ 8

Если eclipse Java build path сопоставлен с 7, 8 и в свойствах Project pom.xml Maven java.version упоминается более высокая версия Java (9,10,11 и т.д.,), Чем 7,8, вам необходимо обновить ее в pom. XML файл.

В Eclipse, если Java сопоставлена с Java версии 11, а в pom.xml она сопоставлена с Java версии 8. Обновите поддержку Eclipse до Java 11, выполнив следующие шаги в справке IDE затмения → Установить новое программное обеспечение ->

Вставьте следующую ссылку http://download.eclipse.org/eclipse/updates/4.9-P-builds при работе с

или же

Добавить (откроется всплывающее окно) ->

Name: поддержка Java 11 Location: http://download.eclipse.org/eclipse/updates/4.9-P-builds

затем обновите версию Java в свойствах Maven файла pom.xml, как показано ниже

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

Наконец, щелкните правой кнопкой мыши на проекте Debug as → Maven clean, шаги сборки Maven.

Ответ 9

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

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

    File → 'Invalidate Caches/Restart'

ИЛИ ЖЕ

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

    compile project(':anotherProject')

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

Ответ 10

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

Ответ 11

Вы скомпилировали свой код, используя maven compile, а затем использовали maven test, чтобы он работал нормально. Теперь, если вы что-то изменили в своем коде, а затем без компиляции запускаете его, вы получите эту ошибку.

Решение: Снова скомпилируйте и запустите тест. Для меня это сработало так.

Ответ 12

В моем случае - я должен был выполнить следующие операции:

  1. Переместите файл context.xml из src/java/package в каталог resource (IntelliJ IDE)
  2. Очистить каталог target.

Ответ 13

РЕШИТЬ

Выберите Build ->Rebuild Project, чтобы решить его.

Ответ 14

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

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

Ответ 15

Вы также можете получить эту ошибку, если вы забыли новую, как в:

int я = Integer(); ---- >> должно быть " new Integer() "

(Вот почему я получаю ошибку в моем случае)