Что означает "Не удалось найти или загрузить основной класс"?
Распространенная проблема, с которой сталкиваются начинающие разработчики Java, заключается в том, что их программы не запускаются с сообщением об ошибке: Could not find or load main class ...
Что это значит, что вызывает это и как вы должны это исправить?
Переведено автоматически
Ответ 1
java <class-name>
Синтаксис командыПрежде всего, вам нужно понять правильный способ запуска программы с помощью команды java
(или javaw
).
Обычный синтаксис1 таков:
java [ <options> ] <class-name> [<arg> ...]
где <option>
- параметр командной строки (начинающийся с символа "-"), <class-name>
- полное имя класса Java и <arg>
- произвольный аргумент командной строки, который передается вашему приложению.
1 - Есть некоторые другие синтаксисы, которые описаны ближе к концу этого ответа.
Полное имя (FQN) для класса обычно записывается так, как вы бы делали в исходном коде Java; например
packagename.packagename2.packagename3.ClassName
Однако некоторые версии java
команды позволяют использовать косые черты вместо точек; например
packagename/packagename2/packagename3/ClassName
который (что сбивает с толку) выглядит как путь к файлу, но таковым не является. Обратите внимание, что термин полное имя является стандартной терминологией Java ... это не то, что я просто придумал, чтобы сбить вас с толку :-)
Вот пример того, как должна выглядеть java
команда:
java -Xmx100m com.acme.example.ListUsers fred joe bert
Вышесказанное приведет к тому, что java
команда выполнит следующее:
com.acme.example.ListUsers
класса.main
метод с сигнатурой, возвращаемым типом и модификаторами, заданными public static void main(String[])
. (Обратите внимание, имя аргумента метода НЕ является частью подписи.)String[]
.Когда вы получаете сообщение "Не удалось найти или загрузить основной класс ...", это означает, что первый шаг завершился неудачей. Команде java
не удалось найти класс. И действительно, "..." в сообщении будет полным именем класса, который java
ищет.
Итак, почему он может быть не в состоянии найти класс?
Первая вероятная причина заключается в том, что вы, возможно, указали неправильное имя класса. (Или ... правильное имя класса, но в неправильной форме.) Учитывая приведенный выше пример, вот множество неправильных способов указать имя класса:
Пример # 1 - простое имя класса:
java ListUser
Когда класс объявлен в пакете, таком как com.acme.example
, вы должны использовать полное имя класса, включая имя пакета в java
команде; например
java com.acme.example.ListUser
Пример # 2 - имя файла или пути вместо имени класса:
java ListUser.class
java com/acme/example/ListUser.class
Пример # 3 - имя класса с неправильной оболочкой:
java com.acme.example.listuser
Пример # 4 - опечатка
java com.acme.example.mistuser
Пример # 5 - исходное имя файла (за исключением Java 11 или более поздней версии; см. Ниже)
java ListUser.java
Пример # 6 - вы полностью забыли название класса
java lots of arguments
Вторая вероятная причина заключается в том, что имя класса указано правильно, но java
команда не может найти класс. Чтобы понять это, вам нужно понять концепцию "пути к классу". Это хорошо объясняется документацией Oracle:
java
Документация по командеИтак ... если вы указали имя класса правильно, следующее, что нужно проверить, - это правильно ли вы указали путь к классу:
java
команды. Убедитесь, что имена каталогов и JAR-файлов указаны правильно.java
команды.;
в Windows и :
в других. Если вы используете неправильный разделитель для вашей платформы, вы не получите явного сообщения об ошибке. Вместо этого вы получите несуществующий файл или каталог по пути, который будет автоматически проигнорирован.)Когда вы помещаете каталог в classpath , он условно соответствует корню в пространстве полных имен. Классы располагаются в структуре каталогов под этим корнем, путем сопоставления полного имени с именем пути. Так, например, если "/ usr / local / acme / classes" находится в пути к классу, то когда JVM ищет класс с именем com.acme.example.Foon
, он будет искать файл ".class" с этим путем:
/usr/local/acme/classes/com/acme/example/Foon.class
Если бы вы поместили "/ usr / local / acme / classes / com / acme / example" в classpath , то JVM не смогла бы найти класс.
Если ваш полный код classes равен com.acme.example.Foon
, то JVM будет искать "Foon.class" в каталоге "com /acme /example":
Если ваша структура каталогов не соответствует названию пакета в соответствии с приведенным выше шаблоном, JVM не найдет ваш класс.
Если вы попытаетесь переименовать класс, переместив его, это также завершится неудачей ... но stacktrace исключения будет другим. Он может сказать что-то вроде этого:
Caused by: java.lang.NoClassDefFoundError: <path> (wrong name: <name>)
потому что FQN в файле класса не соответствует тому, что ожидает найти загрузчик классов.
Чтобы привести конкретный пример, предположим, что:
com.acme.example.Foon
класс,/usr/local/acme/classes/com/acme/example/Foon.class
,/usr/local/acme/classes/com/acme/example/
,тогда:
# wrong, FQN is needed
java Foon
# wrong, there is no `com/acme/example` folder in the current working directory
java com.acme.example.Foon
# wrong, similar to above
java -classpath . com.acme.example.Foon
# fine; relative classpath set
java -classpath ../../.. com.acme.example.Foon
# fine; absolute classpath set
java -classpath /usr/local/acme/classes com.acme.example.Foon
Примечания:
-classpath
параметр может быть сокращен до -cp
. Проверьте соответствующие записи руководства для java
, javac
и так далее.Путь к классу должен включать все другие (несистемные) классы, от которых зависит ваше приложение. (Системные классы находятся автоматически, и вам редко приходится беспокоиться об этом.) Для корректной загрузки основного класса JVM необходимо найти:
(Примечание: спецификации JLS и JVM допускают некоторую возможность для JVM загружать классы "лениво", и это может повлиять на возникновение исключения classloader.)
Иногда случается, что кто-то помещает файл исходного кода не в ту папку в своем дереве исходного кода или не учитывает package
объявление. Если вы сделаете это в IDE, компилятор IDE немедленно сообщит вам об этом. Аналогично, если вы используете приличный инструмент сборки Java, инструмент будет запущен javac
таким образом, чтобы обнаружить проблему. Однако, если вы создаете свой Java-код вручную, вы можете сделать это таким образом, что компилятор не заметит проблему, и результирующий файл ".class" окажется не в том месте, где вы ожидаете его найти.
Нужно многое проверить, и легко что-то пропустить. Попробуйте добавить -Xdiag
опцию в java
командную строку (как первое, что следует после java
). Он выдаст различные сведения о загрузке класса, и это может дать вам подсказки относительно того, в чем заключается реальная проблема.
Также рассмотрите возможные проблемы, вызванные копированием и вставкой невидимых символов или символов, отличных от ASCII, с веб-сайтов, документов и т.д. И рассмотрите "гомоглифы", где две буквы или символа выглядят одинаково ... но это не так.
Вы можете столкнуться с этой проблемой, если у вас неверные подписи в META-INF/*.SF
. Вы можете попробовать открыть файл .jar в вашем любимом ZIP-редакторе и удалять файлы из META-INF
до тех пор, пока не останется только ваш MANIFEST.MF
. Однако в целом это НЕ РЕКОМЕНДУЕТСЯ. (Неверная подпись может быть результатом того, что кто-то внедрил вредоносное ПО в исходный подписанный файл JAR. Если вы удалите неверную подпись, вы заразите вредоносным ПО свое приложение!) Рекомендуемый подход заключается в том, чтобы получить файлы JAR с действительными сигнатурами или перестроить их из (аутентичного) исходного кода.
Наконец, вы, очевидно, можете столкнуться с этой проблемой, если в MANIFEST.MF
файле есть синтаксическая ошибка (см. https://javalang.ru/a/67145190/139985).
java
Существует три альтернативных синтаксиса для запуска Java- программ с использованием java command
.
Синтаксис, используемый для запуска "исполняемого" JAR-файла, следующий:
java [ <options> ] -jar <jar-file-name> [<arg> ...]
например
java -Xmx100m -jar /usr/local/acme-example/listuser.jar fred
Имя класса точки входа (т.е. com.acme.example.ListUser
) и путь к классу указаны в МАНИФЕСТЕ файла JAR. Все, что вы указываете в качестве пути к классу в командной строке, игнорируется с таким синтаксисом: используется только Class-Path
запись в манифесте (и, транзитивно, в любых файлах JAR, на которые ссылается эта запись). Обратите также внимание, что URL-адреса в этом Class-Path
указаны относительно местоположения JAR, в котором он содержится.
Синтаксис для запуска приложения из модуля (Java 9 и более поздних версий) следующий:
java [ <options> ] --module <module>[/<mainclass>] [<arg> ...]
Имя класса entrypoint либо определяется <module>
самим, либо задается необязательным <mainclass>
.
Начиная с Java 11, вы можете использовать команду java
для компиляции и запуска одного файла исходного кода, используя следующий синтаксис:
java [ <options> ] <sourcefile> [<arg> ...]
где <sourcefile>
находится (обычно) файл с суффиксом ".java".
Для получения более подробной информации, пожалуйста, обратитесь к официальной документации по java
команде для версии Java, которую вы используете.
Типичная Java IDE поддерживает запуск Java-приложений в самой IDE JVM или в дочерней JVM. Они обычно защищены от этого конкретного исключения, потому что IDE использует свои собственные механизмы для построения пути к классу среды выполнения, идентификации основного класса и создания java
командной строки.
Однако это исключение все еще возможно, если вы делаете что-то за пределами IDE. Например, если вы предварительно настроили средство запуска приложений для вашего Java-приложения в Eclipse, а затем переместили JAR-файл, содержащий "основной" класс, в другое место в файловой системе, не сообщив об этом Eclipse, Eclipse невольно запустит JVM с неправильным путем к классу.
Короче говоря, если вы столкнулись с этой проблемой в IDE, проверьте наличие таких вещей, как устаревшее состояние IDE, неработающие ссылки на проекты или неработающие конфигурации запуска.
IDE также может просто запутаться. IDE - это чрезвычайно сложные части программного обеспечения, состоящие из множества взаимодействующих частей. Многие из этих частей используют различные стратегии кэширования, чтобы сделать IDE в целом отзывчивой. Иногда они могут работать неправильно, и одним из возможных симптомов являются проблемы при запуске приложений. Если вы подозреваете, что это может происходить, стоит попробовать другие вещи, такие как перезапуск вашей IDE, перестройка проекта и так далее.
Ответ 2
Если ваше имя исходного кода равно HelloWorld.java, ваш скомпилированный код будет HelloWorld.class
.
Вы получите эту ошибку, если вызовете ее с помощью:
java HelloWorld.class
Вместо этого используйте это:
java HelloWorld
Ответ 3
Если ваши классы находятся в пакетах, тогда вам нужно cd
перейти в корневой каталог вашего проекта и запустить, используя полное имя класса (packageName.MainClassName).
Пример:
Мои классы находятся здесь:
D:\project\com\cse\
Полное имя моего основного класса:
com.cse.Main
Итак, я cd
возвращаюсь в корневой каталог проекта:
D:\project
Затем выполните команду java
:
java com.cse.Main
Этот ответ предназначен для того, чтобы избавить начинающих Java-программистов от разочарования, вызванного распространенной ошибкой. Я рекомендую вам прочитать принятый ответ для получения более глубоких знаний о пути к классам Java.
Ответ 4
Если у вас есть package
ключевое слово в вашем исходном коде (основной класс определен в пакете), вы должны запустить его в иерархическом каталоге, используя полное имя класса (packageName.MainClassName
).
Предположим, что существует файл исходного кода (Main.java):
package com.test;
public class Main {
public static void main(String[] args) {
System.out.println("salam 2nya\n");
}
}
Для запуска этого кода вы должны поместить Main.Class
в каталог package like:
C:\Users\workspace\testapp\com\test\Main.Java
Затем измените текущий каталог терминала на корневой каталог проекта:
cd C:\Users\workspace\testapp
И, наконец, запустите код:
java com.test.Main
Если у вас нет никакого пакета в имени вашего исходного кода, возможно, вы ошиблись с неверной командой. Предположим, что ваше имя файла Java Main.java
, после компиляции:
javac Main.java
ваш скомпилированный код будет Main.class
Вы получите эту ошибку, если вызовете ее с помощью:
java Main.class
Вместо этого используйте это:
java Main