Что означает ошибка компиляции "Не удается найти символ"?
Пожалуйста, объясните следующее об ошибке "Не удается найти символ":
- Что означает эта ошибка?
- Какие вещи могут вызвать эту ошибку?
- Как программист исправляет эту ошибку?
Этот вопрос предназначен для того, чтобы стать исчерпывающим вопросом об ошибках компиляции "not find symbol" в Java.
24 ответа
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()
,
Для идентификаторов, которые должны быть именами классов:
- Возможно, вы забыли импортировать класс.
- Возможно, вы использовали импорт "звезда", но класс не определен ни в одном из импортированных вами пакетов.
Возможно, вы забыли
new
как в:String s = String(); // should be 'new String()'
Для случаев, когда тип или экземпляр не имеют члена, которого вы ожидали иметь:
- Возможно, вы объявили вложенный класс или универсальный параметр, который скрывает тип, который вы намеревались использовать.
- Возможно, вы отслеживаете статическую переменную или переменную экземпляра.
- Возможно, вы импортировали неправильный тип; например, из-за завершения IDE или автокоррекции.
- Возможно, вы используете (компилируете) неправильную версию API.
- Возможно, вы забыли привести свой объект к соответствующему подклассу.
Проблема часто заключается в сочетании вышеперечисленного. Например, может быть, вы "звезда" импортированы java.io.*
а затем попытался использовать Files
класс... который находится в java.nio
не java.io
, Или, может быть, вы хотели написать File
... который является классом в 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
петля. Так что код на самом деле означает это:
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. Неясные причины
Вот пара случаев, когда "Не удается найти символ", казалось бы, необъяснимо... пока вы не посмотрите ближе.
Неверные зависимости: если вы используете IDE или инструмент сборки, который управляет путем сборки и зависимостями проекта, возможно, вы допустили ошибку с зависимостями; например, исключил зависимость или выбрал неправильную версию. Если вы используете инструмент сборки (Ant, Maven, Gradle и т. Д.), Проверьте файл сборки проекта. Если вы используете IDE, проверьте конфигурацию пути сборки проекта.
Вы не перекомпилируете: иногда случается, что новые Java-программисты не понимают, как работает цепочка инструментов Java, или не реализуют повторяемый "процесс сборки"; например, используя IDE, Ant, Maven, Gradle и так далее. В такой ситуации программист может в итоге гоняться за хвостом в поисках иллюзорной ошибки, которая на самом деле вызвана неправильной перекомпиляцией кода и тому подобным...
Проблема с более ранней сборкой: возможно, что более ранняя сборка завершилась неудачно, что дало файл JAR с отсутствующими классами. Такой сбой, как правило, будет замечен, если вы используете инструмент сборки. Однако, если вы получаете файлы JAR от кого-то другого, вы зависите от их правильной сборки и замечаете ошибки. Если вы подозреваете это, используйте
tar -tvf
перечислить содержимое подозрительного файла JAR.Проблемы IDE: Люди сообщали о случаях, когда их IDE путается, и компилятор в IDE не может найти класс, который существует... или обратная ситуация.
Это может произойти, если кэши IDE не синхронизированы с файловой системой. Есть конкретные способы, чтобы исправить это.
Это может быть ошибка IDE. Например, @Joel Costigliola описывает сценарий, в котором Eclipse неправильно обрабатывает "тестовое" дерево Maven: см. Этот ответ.
Пересмотр системных классов: я видел случаи, когда компилятор жалуется, что
substring
неизвестный символ в чем-то вроде следующегоString s = ... String s1 = s.substring(1);
Оказалось, что программист создал собственную версию
String
и что его версия класса не определилаsubstring
методы.Урок: не определяйте свои собственные классы с такими же именами, как у обычных библиотечных классов!
Гомоглифы: если вы используете кодировку UTF-8 для своих исходных файлов, возможно, что идентификаторы выглядят одинаково, но на самом деле отличаются, потому что они содержат гомоглифы. Смотрите эту страницу для получения дополнительной информации.
Вы можете избежать этого, ограничив себя ASCII или Latin-1 в качестве кодировки исходного файла и используя Java
\uxxxx
убегает для других персонажей.
1 - Если, возможно, вы видите это в исключительной ситуации или сообщении об ошибке во время выполнения, то либо вы сконфигурировали IDE для запуска кода с ошибками компиляции, либо ваше приложение генерирует и компилирует код... во время выполнения.
2 - Три основных принципа гражданского строительства: вода не течет в гору, доска сильнее на ее стороне, и вы не можете толкнуть веревку.
Вы также получите эту ошибку, если вы забудете new
:
String s = String();
против
String s = new String();
Еще один пример "Переменная выходит за рамки"
Как я уже видел подобные вопросы несколько раз, может быть, еще один пример того, что незаконно, даже если это может показаться нормальным.
Рассмотрим этот код:
if(somethingIsTrue()) {
String message = "Everything is fine";
} else {
String message = "We have an error";
}
System.out.println(message);
Это неверный код. Потому что ни одна из названных переменных message
виден за пределами их соответствующей области видимости - которые будут окружающие скобки {}
в этом случае.
Вы можете сказать: "Но переменная с именем message определяется в любом случае - поэтому сообщение определяется после if
".
Но ты ошибаешься.
Ява не имеет 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 выдаст "Cannot find symbol".
Основная причина: 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);
}
}
Теперь посмотрим на новый вывод...
Хорошо, успешно удалось решить эту ошибку. В то же время, если вы можете получить что-то "не могу найти метод" или "не можете найти класс", сначала определите класс или метод, а затем используйте это..
Там могут быть различные сценарии, как люди упоминали выше. Несколько вещей, которые помогли мне решить эту проблему.
Если вы используете IntelliJ
File -> 'Invalidate Caches/Restart'
ИЛИ ЖЕ
Указанный класс находился в другом проекте, и эта зависимость не была добавлена в файл сборки Gradle моего проекта. Поэтому я добавил зависимость, используя
compile project(':anotherProject')
и это сработало. НТН!
Если вы получаете эту ошибку в сборке где-то еще, а ваша IDE говорит, что все отлично, то убедитесь, что вы используете одинаковые версии Java в обоих местах.
Например, Java 7 и Java 8 имеют разные API, поэтому вызов несуществующего API в более старой версии Java может вызвать эту ошибку.
Если 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 eclipse -> Установить новое программное обеспечение ->
Вставьте следующую ссылку 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.
Я тоже получал эту ошибку. (за что я погуглил и меня направили на эту страницу)
Проблема: я вызывал статический метод, определенный в классе проекта A, из класса, определенного в другом проекте B. Я получил следующую ошибку:
error: cannot find symbol
Решение: я решил эту проблему, сначала создав проект, в котором определяется метод, а затем проект, из которого вызывался метод.
Вы скомпилировали свой код с помощью компиляции maven, а затем использовали тест maven для запуска, он работал нормально. Теперь, если вы что-то изменили в своем коде, а затем без компиляции вы его запускаете, вы получите эту ошибку.
Решение: снова скомпилируйте его и запустите тест. Для меня это сработало.
В моем случае - мне пришлось выполнить следующие операции:
- Переехать
context.xml
файл изsrc/java/package
кresource
каталог (IntelliJ IDE) - Чистый
target
каталог.
Я получал ошибку ниже
java: cannot find symbol
symbol: class __
Чтобы исправить это
Я попытался включить lambok, перезапустил intellij и т. д., но у меня сработало ниже.
Intellij Preferences ->Compiler -> Shared Build process VM Options и установите для него значение
-Djps.track.ap.dependencies=false
чем бежать
mvn clean install
Re: 4.4: более ранняя проблема сборки в отличном ответе Стивена С.:
Я столкнулся с этим сценарием при разработке приложения osgi.
У меня был java-проект
A
это была зависимость от . При строительстве
B
, была ошибка:
Compilation failure: org.company.projectA.bar.xyz does not exist
Но в eclipse вообще не было проблем с компиляцией.
Расследование
Когда я заглянул, там были занятия для
org.company.projectA.foo.abc
но ни для
org.company.projectA.bar.xyz
.
Причина пропуска занятий заключалась в том, что в
A/pom.xml
, была запись для экспорта соответствующих пакетов.
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
...
<configuration>
<instructions>
....
<Export-Package>org.company.projectA.foo.*</Export-Package>
</instructions>
</configuration>
</plugin>
Решение
Добавьте отсутствующие пакеты следующим образом:
<Export-Package>org.company.projectA.foo.*,org.company.projectA.bar.*</Export-Package>
и все восстановить.
Сейчас
A.jar
включает все ожидаемые классы, и все компилируется.
Для подсказок, посмотрите ближе на имя класса, которое выдает ошибку и номер строки, пример: Ошибка компиляции [ОШИБКА] \ Applications\xxxxx.java:[44,30] Ошибка: не удается найти символ
Еще одна причина - неподдерживаемый метод для java-версии, скажем, jdk7 против 8. Проверьте ваш%JAVA_HOME%.
Мы получили ошибку в проекте Java, который настроен как многопроектная сборка Gradle. Оказалось, что в одном из подпроектов отсутствовал плагин Gradle Java Library. Это препятствовало тому, чтобы файлы классов подпроекта были видны другим проектам в сборке.
После добавления плагина библиотеки Java в подпроект build.gradle
таким образом ошибка исчезла:
plugins {
...
id 'java-library'
}
Необязательный.isEmpty()
я с удовольствием использовал!Optional.isEmpty()
в моей среде IDE, и он отлично работает, так как я компилировал/запускал свой проект с >=JDK11
. Теперь, когда я используюGradle
в командной строке (работает наJDK8
), я получил неприятную ошибку в задаче компиляции.
Почему?
Из документов (обратите внимание на последнюю строку):
boolean java.util.Optional.isEmpty()
If a value is not present, returns true, otherwise false.
Returns:true if a value is not present, otherwise false
Since:11
как сказал Стивен:
Ошибка «Не удается найти символ» связана с идентификаторами. Когда ваш код компилируется, компилятор должен определить, что означает каждый идентификатор в вашем коде.
Ошибка «Не удается найти символ» означает, что компилятор не может этого сделать. Ваш код, похоже, относится к чему-то, что компилятор не понимает.
Я получил эту ошибку, когда использовал круглые скобки для указания элементов массива вместо квадратных скобок. Так что, возможно, вы что-то написали неправильно.
Что они имеют в виду?
Все три утверждения означают одно и то же: «Невозможно найти символ», «Невозможно разрешить символ» и «Символ не найден».Теперь смысл ошибки заключается в том, что компилятор не может понять ссылку на определенный символ. Или просто компилятор не может этого сделать.
Причина и как исправить
Если вы получаете эту ошибку в сборке где-то еще, а ваша IDE говорит, что все в порядке, убедитесь, что вы используете одни и те же версии Java в обоих местах. Если вы столкнулись с этой ошибкой в сборке в другом месте, и ваша IDE сообщает, что все в порядке, проверьте, используется ли одна и та же версия Java в обоих местах.
Например, Java 7 и Java 8 имеют разные API, поэтому вызов несуществующего API в более старой версии Java может вызвать эту ошибку. Например, Java 7 и Java 8 имеют разные API, поэтому вызов несуществующего API в более старой версии Java вызовет эту ошибку.
Решил эту ошибку вот так... Безумие андроида. У меня было имя пакета как "Адаптер", и я реорганизовал имя для адаптера с "а" вместо "А" и решил ошибку.
Это означает, что компилятор не может найти эту переменную, класс или оператор.
Как исправить? Я столкнулся с этой ошибкой и попробовал все решения.
Что сработало для меня, так это переименовать мой класс в любое другое имя и предположить, что это сработало.
Кажется, проблема с компилятором.
Я получил эту ошибку после импорта файлов классов в мой проект Eclipse (включая файл основного класса). После проб и ошибок я исправил это, переместив файлы классов, которые вызвали эту ошибку, в мою папку src и установив в моих конфигурациях запуска точное имя моего основного класса.
У меня была такая же проблема при компиляции моего проекта, я проверил свою версию компилятора java, раньше он работал на java 1.8, но случайно установил java 17, я изменил его обратно на версию 1.8, и моя проблема решена.
Вы также можете получить эту ошибку, если вы забыли новую, как в:
int i = Integer (); ---- >> должно быть "new Integer ()"
(Вот почему я получаю ошибку в моем случае)