Что означает ошибка «Не удается найти символ» или «Не удается разрешить символ»?
Пожалуйста, объясните следующее об ошибках «Не удается найти символ», «Не удается разрешить символ» или «Символ не найден»:
- Что они имеют в виду?
- Что может их вызвать?
- Как программист их исправляет?
Этот вопрос предназначен для того, чтобы дать исчерпывающий ответ на вопросы об этих распространенных ошибках компиляции в Java.
Ответы
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. Неизвестные причины
Вот пара случаев, когда «Невозможно найти символ» кажется необъяснимым ... пока вы не присмотритесь.
Неправильные зависимости : если вы используете IDE или инструмент сборки, который управляет путем сборки и зависимостями проекта, возможно, вы ошиблись с зависимостями; например, не учитывает зависимость или выбрала неправильную версию. Если вы используете инструмент сборки (Ant, Maven, Gradle и т. Д.), Проверьте файл сборки проекта. Если вы используете IDE, проверьте конфигурацию пути сборки проекта.
Вы не перекомпилируете : иногда случается, что новые программисты на Java не понимают, как работает цепочка инструментов Java, или не реализовали повторяющийся «процесс сборки»; например, используя IDE, Ant, Maven, Gradle и так далее. В такой ситуации программист может преследовать свой хвост в поисках иллюзорной ошибки, которая на самом деле вызвана неправильной перекомпиляцией кода и тому подобное ...
Проблема более ранней сборки : возможно, что предыдущая сборка завершилась неудачно из-за того, что в файле JAR были пропущены классы. Такой сбой обычно можно было бы заметить, если бы вы использовали инструмент сборки. Однако, если вы получаете файлы JAR от кого-то другого, вы зависите от их правильного построения и выявления ошибок. Если вы подозреваете это, используйте
tar -tvf
для вывода содержимого подозрительного файла JAR.Проблемы с IDE : люди сообщают о случаях, когда их IDE сбивается с толку, и компилятор в IDE не может найти существующий класс ... или обратная ситуация.
Это могло произойти, если в IDE была настроена неправильная версия JDK.
Это могло произойти, если кеши IDE не синхронизированы с файловой системой. Есть специальные способы IDE исправить это.
Это может быть ошибка IDE. Например, @Joel Costigliola описывает сценарий, в котором Eclipse некорректно обрабатывает "тестовое" дерево Maven: см. Этот ответ .
Проблемы с Android : когда вы программируете для Android и у вас возникают ошибки «Не удается найти символ»
R
, имейте в виду, чтоR
символы определяютсяcontext.xml
файлом. Убедитесь, что вашcontext.xml
файл правильный и находится в правильном месте, и что соответствующийR
файл класса был сгенерирован / скомпилирован. Обратите внимание, что символы Java чувствительны к регистру, поэтому соответствующие идентификаторы XML также чувствительны к регистру.Другие ошибки символов на Android, вероятно, связаны с ранее упомянутыми причинами; например, отсутствующие или неправильные зависимости, неправильные имена пакетов, метод или поля, которых нет в конкретной версии API, орфографические / типографические ошибки и т. д.
Переопределение системных классов : я видел случаи, когда компилятор жалуется, что
substring
это неизвестный символ примерно в следующемString s = ... String s1 = s.substring(1);
Оказалось, что программист создал свою собственную версию,
String
и что его версия класса не определялаsubstring
методы.Урок: не определяйте свои собственные классы с теми же именами, что и классы общей библиотеки!
Гомоглифы: если вы используете кодировку UTF-8 для своих исходных файлов, можно иметь идентификаторы, которые выглядят одинаково, но на самом деле отличаются, потому что они содержат гомоглифы. См. Эту страницу для получения дополнительной информации.
Вы можете избежать этого, ограничившись ASCII или Latin-1 в качестве кодировки исходного файла и используя
\uxxxx
escape-символы Java для других символов.
1 - Если, возможно, вы бы увидеть это в исключение во время выполнения или сообщение об ошибке, то либо вы настроили IDE для кода выполнения с ошибками компиляции, или приложение генерирует и компиляции кода .. во время выполнения.
2 - Три основных принципа гражданского строительства: вода не течет в гору, доска на боку прочнее, и на веревке нельзя давить .
Вы также получите эту ошибку, если забудете new
:
String s = String();
против
String s = new String();
потому что вызов без new
ключевого слова будет пытаться найти (локальный) метод, вызываемый String
без аргументов, и эта сигнатура метода, вероятно, не определена.
Еще один пример «Переменная выходит за рамки»
Поскольку я уже несколько раз встречал подобные вопросы, может быть, это еще один пример того, что незаконно, даже если это может показаться нормальным.
Рассмотрим этот код:
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);
Один из способов получить эту ошибку в Eclipse:
- Определите класс
A
вsrc/test/java
. - Определите другой класс
B
вsrc/main/java
этом классеA
.
Результат: Eclipse скомпилирует код, но maven выдаст «Невозможно найти символ».
Основная причина: Eclipse использует комбинированный путь сборки для основного и тестового деревьев. К сожалению, он не поддерживает использование разных путей сборки для разных частей проекта Eclipse, чего требует Maven.
Решение :
- Не определяйте свои зависимости таким образом; т.е. не делайте этой ошибки.
- Регулярно создавайте свою кодовую базу с помощью Maven, чтобы своевременно исправить эту ошибку. Один из способов сделать это - использовать CI-сервер.
«Не удается найти» означает, что компилятор, который не может найти подходящую переменную, метод, класс и т. Д., Если вы получили сообщение об ошибке, в первую очередь вам нужно найти строку кода, в которой отображается сообщение об ошибке. может определить, какая переменная, метод или класс не определены перед их использованием. После подтверждения инициализировать эту переменную, метод или класс можно будет использовать для дальнейшего использования ... Рассмотрим следующий пример.
Я создам демонстрационный класс и напечатаю имя ...
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);
}
}
Теперь посмотрим на новый вывод ...
Хорошо. Эта ошибка успешно решена .. В то же время, если вы могли получить что-то «не могу найти метод» или «не могу найти класс», сначала определите класс или метод, а затем используйте это ..
Если вы получаете эту ошибку в сборке где-то еще, а ваша IDE говорит, что все в порядке, убедитесь, что вы используете одни и те же версии Java в обоих местах.
Например, Java 7 и Java 8 имеют разные API, поэтому вызов несуществующего API в более старой версии Java вызовет эту ошибку.
Решено
Использование IntelliJ
Выберите Build -> Rebuild Project решит эту проблему.
Я тоже получал эту ошибку. (для чего я погуглил, и меня перенаправили на эту страницу)
Проблема: я вызывал статический метод, определенный в классе проекта A, из класса, определенного в другом проекте B. Я получал следующую ошибку:
error: cannot find symbol
Решение: я решил эту проблему, создав сначала проект, в котором определен метод, а затем проект, из которого метод был вызван.
Если путь сборки 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
Как уже упоминалось выше, могут быть разные сценарии. Несколько вещей, которые помогли мне решить эту проблему.
Если вы используете IntelliJ
File -> 'Invalidate Caches/Restart'
ИЛИ
Указанный класс находился в другом проекте, и эта зависимость не была добавлена в файл сборки Gradle моего проекта. Итак, я добавил зависимость, используя
compile project(':anotherProject')
и это сработало. HTH!
вы скомпилировали свой код с помощью компиляции maven, а затем использовали тест maven, чтобы он работал нормально. Теперь, если вы что-то изменили в своем коде, а затем без компиляции вы его запускаете, вы получите эту ошибку.
Решение: снова скомпилируйте его и запустите тест. Для меня это сработало.
В моем случае - мне пришлось выполнить следующие операции:
- Переместить
context.xml
файл изsrc/java/package
вresource
каталог (IntelliJ IDE) - Чистый
target
каталог.
Для подсказок внимательно посмотрите на имя класса, которое вызывает ошибку, и номер строки, например: Ошибка компиляции [ERROR] \ applications \ xxxxx.java: [44,30] error: не удается найти символ
Еще одна причина - неподдерживаемый метод для версии java, например, jdk7 vs 8. Проверьте свой% JAVA_HOME%
Мы получили ошибку в проекте Java, который настроен как многопроектная сборка Gradle. Оказалось, что в одном из подпроектов отсутствовал плагин Gradle Java Library . Это препятствовало тому, чтобы файлы классов подпроекта были видны другим проектам в сборке.
После добавления плагина библиотеки Java в подпроект build.gradle
следующим образом ошибка исчезла:
plugins {
...
id 'java-library'
}
Решил эту ошибку вот так ... Безумие андроида. У меня было имя пакета как «Адаптер», и я реорганизовал имя для адаптера с «а» вместо «А» и решил ошибку.