Что означает ошибка «Не удается найти символ» или «Не удается разрешить символ»?

Sep 07 2014

Пожалуйста, объясните следующее об ошибках «Не удается найти символ», «Не удается разрешить символ» или «Символ не найден»:

  • Что они имеют в виду?
  • Что может их вызвать?
  • Как программист их исправляет?

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

Ответы

441 StephenC Sep 07 2014 at 08:12

0. Есть ли разница между двумя ошибками?

На самом деле, нет. «Не удается найти символ», «Не удается найти символ» и «Символ не найден» означают одно и то же. В разных компиляторах Java используется разная фразеология.

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; например 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на 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: см. Этот ответ .

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

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

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

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

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

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

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

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


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

2 - Три основных принципа гражданского строительства: вода не течет в гору, доска на боку прочнее, и на веревке нельзя давить .

26 thinkterry Apr 17 2015 at 15:50

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

String s = String();

против

String s = new String();

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

14 Jan Dec 06 2015 at 16:19

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

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

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

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);
10 JoelCostigliola May 13 2016 at 17:09

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

  1. Определите класс Aв src/test/java.
  2. Определите другой класс Bв src/main/javaэтом классе A.

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

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

Решение :

  1. Не определяйте свои зависимости таким образом; т.е. не делайте этой ошибки.
  2. Регулярно создавайте свою кодовую базу с помощью Maven, чтобы своевременно исправить эту ошибку. Один из способов сделать это - использовать CI-сервер.
5 GT_hash Jun 30 2018 at 18:09

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

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

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

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

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

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

             String name="smith";

             System.out.print(name);
      }
}

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

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

3 JonathanLin Mar 08 2016 at 12:58

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

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

3 Ajay Oct 10 2019 at 19:07

Решено

Использование IntelliJ

Выберите Build -> Rebuild Project решит эту проблему.

2 DivyaJose Sep 28 2016 at 21:59

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

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

error: cannot find symbol

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

2 UdayKiranPulipati Jan 24 2019 at 18:18

Если путь сборки Java eclipse сопоставлен с 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, выполнив следующие шаги в Справке Eclipse IDE -> Установить новое программное обеспечение ->

Вставьте следующую ссылку http://download.eclipse.org/eclipse/updates/4.9-P-builds at Work With

или

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

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

1 avp Aug 18 2018 at 08:45

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

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

    File -> 'Invalidate Caches/Restart'

ИЛИ

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

    compile project(':anotherProject')

и это сработало. HTH!

1 ANILKUMAR Aug 07 2019 at 11:59

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

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

1 VIPINKUMAR Sep 08 2019 at 14:50

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

  1. Переместить context.xmlфайл из src/java/packageв resourceкаталог (IntelliJ IDE)
  2. Чистый targetкаталог.
Striker Sep 06 2017 at 19:47

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

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

sakra Jul 20 2020 at 19:31

Мы получили ошибку в проекте Java, который настроен как многопроектная сборка Gradle. Оказалось, что в одном из подпроектов отсутствовал плагин Gradle Java Library . Это препятствовало тому, чтобы файлы классов подпроекта были видны другим проектам в сборке.

После добавления плагина библиотеки Java в подпроект build.gradleследующим образом ошибка исчезла:

plugins {
    ...
    id 'java-library'
}
FelipeFranco Nov 20 2020 at 04:03

Решил эту ошибку вот так ... Безумие андроида. У меня было имя пакета как «Адаптер», и я реорганизовал имя для адаптера с «а» вместо «А» и решил ошибку.