Co oznacza „Nie można znaleźć lub załadować głównej klasy”?

1370

Częstym problemem występującym u nowych programistów Java jest to, że ich programy nie działają z komunikatem o błędzie: Could not find or load main class ...

Co to znaczy, co go powoduje i jak to naprawić?

Stephen C.
źródło
37
Należy pamiętać, że jest to pytanie „samo-odpowiedzi”, które ma być ogólną referencją dla nowych użytkowników Java. Nie mogłem znaleźć istniejącego pytania i odpowiedzi, które odpowiednio to obejmuje (IMO).
Stephen C

Odpowiedzi:

1230

java <class-name>Składnia polecenia

Przede wszystkim musisz zrozumieć prawidłowy sposób uruchamiania programu za pomocą polecenia java(lub javaw).

Normalna składnia 1 jest następująca:

    java [ <options> ] <class-name> [<arg> ...]

gdzie <option>jest opcją wiersza poleceń (zaczynającą się od znaku „-”), <class-name>jest w pełni kwalifikowaną nazwą klasy Java i <arg>jest dowolnym argumentem wiersza poleceń przekazywanym do aplikacji.


1 - Istnieje kilka innych składni opisanych na końcu tej odpowiedzi.

W pełni kwalifikowana nazwa (FQN) dla klasy jest tradycyjnie zapisywana tak jak w kodzie źródłowym Java; na przykład

    packagename.packagename2.packagename3.ClassName

Jednak niektóre wersje javapolecenia pozwalają używać ukośników zamiast kropek; na przykład

    packagename/packagename2/packagename3/ClassName

który (myląco) wygląda jak ścieżka do pliku, ale nie jest nim. Zwróć uwagę, że termin w pełni kwalifikowana nazwa jest standardową terminologią Java ... a nie czymś, co właśnie wymyśliłem, aby cię zdezorientować :-)

Oto przykład, jak javapowinno wyglądać polecenie:

    java -Xmx100m com.acme.example.ListUsers fred joe bert

Powyższe spowoduje, że javapolecenie wykona następujące czynności:

  1. Wyszukaj skompilowaną wersję com.acme.example.ListUsersklasy.
  2. Załaduj klasę.
  3. Sprawdź, czy klasa ma mainmetodę z podpisem , typem zwrotu i modyfikatorami podanymi przez public static void main(String[]). (Uwaga: nazwa argumentu metody NIE jest częścią podpisu).
  4. Wywołaj tę metodę, przekazując jej argumenty wiersza poleceń („fred”, „joe”, „bert”) jako String[].

Powody, dla których Java nie może znaleźć klasy

Gdy pojawi się komunikat „Nie można znaleźć lub załadować głównej klasy ...”, oznacza to, że pierwszy krok nie powiódł się. javaPolecenie nie był w stanie znaleźć klasę. I rzeczywiście, „...” w wiadomości będzie w pełni kwalifikowaną nazwą klasy, której javaszuka.

Dlaczego więc nie może znaleźć klasy?

Powód 1 - popełniłeś błąd przy argumencie nazwy klasy

Pierwszą prawdopodobną przyczyną jest podanie niewłaściwej nazwy klasy. (Lub ... właściwa nazwa klasy, ale w złej formie.) Biorąc pod uwagę powyższy przykład, oto wiele niewłaściwych sposobów określania nazwy klasy:

  • Przykład 1 - prosta nazwa klasy:

    java ListUser

    Gdy klasa jest zadeklarowana w pakiecie takim jak np. com.acme.example, Musisz użyć pełnej nazwy klasy wraz z nazwą pakietu w javapoleceniu; na przykład

    java com.acme.example.ListUser
  • Przykład # 2 - nazwa pliku lub ścieżka zamiast nazwy klasy:

    java ListUser.class
    java com/acme/example/ListUser.class
  • Przykład # 3 - nazwa klasy z niepoprawną obudową:

    java com.acme.example.listuser
  • Przykład # 4 - literówka

    java com.acme.example.mistuser
  • Przykład # 5 - nazwa pliku źródłowego (oprócz Java 11 lub nowszego; patrz poniżej)

    java ListUser.java
  • Przykład # 6 - całkowicie zapomniałeś nazwy klasy

    java lots of arguments

Powód # 2 - ścieżka klasy aplikacji jest niepoprawnie określona

Drugą prawdopodobną przyczyną jest to, że nazwa klasy jest poprawna, ale javapolecenie nie może znaleźć klasy. Aby to zrozumieć, musisz zrozumieć pojęcie „ścieżki klas”. Wyjaśnia to dobrze dokumentacja Oracle:

Więc ... jeśli poprawnie podałeś nazwę klasy, następną rzeczą do sprawdzenia jest poprawne określenie ścieżki klas:

  1. Przeczytaj trzy dokumenty połączone powyżej. (Tak ... PRZECZYTAJ je! Ważne jest, aby programista Java zrozumiał przynajmniej podstawy działania mechanizmów ścieżki klas Java).
  2. Spójrz na wiersz poleceń i / lub zmienną środowiskową CLASSPATH, która obowiązuje po uruchomieniu javapolecenia. Sprawdź, czy nazwy katalogów i nazwy plików JAR są poprawne.
  3. Jeśli w ścieżce klasy znajdują się względne ścieżki, sprawdź, czy poprawnie rozwiązują ... z bieżącego katalogu, który obowiązuje po uruchomieniu javapolecenia.
  4. Sprawdź, czy klasa (wymieniona w komunikacie o błędzie) może znajdować się w efektywnej ścieżce klasy.
  5. Zauważ, że składnia ścieżki klas jest inna dla Windows niż Linux i Mac OS. (Separator ścieżek klas znajduje się ;w systemie Windows i :innych. Jeśli użyjesz niewłaściwego separatora dla swojej platformy, nie otrzymasz wyraźnego komunikatu o błędzie. Zamiast tego otrzymasz ścieżkę, która nie istnieje, w ścieżce, która zostanie po cichu zignorowana .)

Powód # 2a - niewłaściwy katalog znajduje się w ścieżce klasy

Gdy umieścisz katalog w ścieżce klas, teoretycznie odpowiada on katalogowi głównemu kwalifikowanej przestrzeni nazw. Klasy znajdują się w strukturze katalogów poniżej tego katalogu głównego, poprzez mapowanie w pełni kwalifikowanej nazwy na nazwę ścieżki . Na przykład, jeśli „/ usr / local / acme / klas” znajduje się na ścieżce klasy, to kiedy JVM szuka klasy o nazwie com.acme.example.Foon, będzie szukał pliku „.class” o tej nazwie ścieżki:

  /usr/local/acme/classes/com/acme/example/Foon.class

Jeśli umieściłeś „/ usr / local / acme / klas / com / acme / example” na ścieżce klasy, JVM nie byłby w stanie znaleźć klasy.

Powód # 2b - ścieżka podkatalogu nie zgadza się z FQN

Jeśli FQN twoich klas com.acme.example.Foon, to JVM będzie szukać „Foon.class” w katalogu „com / acme / example”:

  • Jeśli struktura katalogów nie odpowiada nazwie pakietu zgodnie z powyższym wzorcem, JVM nie znajdzie twojej klasy.

  • Jeśli spróbujesz zmienić nazwę klasy, przenosząc ją, to również się nie powiedzie ... ale wyjątek stacktrace będzie inny. Można powiedzieć coś takiego:

    Caused by: java.lang.NoClassDefFoundError: <path> (wrong name: <name>)

    ponieważ nazwa FQN w pliku klasy nie zgadza się z tym, czego oczekuje moduł ładujący klasy.

Podając konkretny przykład, załóżmy, że:

  • chcesz prowadzić com.acme.example.Foonklasę,
  • pełna ścieżka pliku jest /usr/local/acme/classes/com/acme/example/Foon.class,
  • Twój bieżący katalog roboczy jest /usr/local/acme/classes/com/acme/example/,

następnie:

# 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

Uwagi:

  • -classpathOpcja może być skrócony do -cpwiększości wydań Java. Sprawdź odpowiednie wpisy dla manualnych java, javaci tak dalej.
  • Zastanów się, wybierając między ścieżkami bezwzględnymi i względnymi. Pamiętaj, że względna nazwa ścieżki może „ulec uszkodzeniu”, jeśli zmieni się bieżący katalog.

Powód # 2c - brak zależności w ścieżce klasy

Ścieżka klasy musi zawierać wszystkie inne (niesystemowe) klasy, od których zależy twoja aplikacja. (Klasy systemowe są lokalizowane automatycznie i rzadko trzeba się tym zajmować.) Aby klasa główna poprawnie się załadowała, JVM musi znaleźć:

(Uwaga: specyfikacje JLS i JVM pozwalają JVM na pewien zakres ładowania klas „leniwie”, co może mieć wpływ, gdy zostanie zgłoszony wyjątek programu ładującego klasy.)

Powód 3 - klasa została zadeklarowana w niewłaściwym pakiecie

Czasami zdarza się, że ktoś umieszcza plik kodu źródłowego w niewłaściwym folderze w drzewie kodu źródłowego lub pomija packagedeklarację. Jeśli zrobisz to w środowisku IDE, kompilator IDE natychmiast o tym powie. Podobnie, jeśli używasz przyzwoitego narzędzia do budowania Java, narzędzie będzie działać javacw sposób, który wykryje problem. Jeśli jednak zbudujesz kod Java ręcznie, możesz to zrobić w taki sposób, aby kompilator nie zauważył problemu, a wynikowy plik „.class” nie znajduje się w miejscu, w którym się spodziewasz.

Nadal nie możesz znaleźć problemu?

Jest wiele rzeczy do sprawdzenia i łatwo coś przeoczyć. Spróbuj dodać -Xdiagopcję do javawiersza poleceń (jako pierwszą rzecz po java). Wyprowadzi różne rzeczy na temat ładowania klas, a to może dać ci wskazówki co do prawdziwego problemu.

Weź również pod uwagę możliwe problemy związane z kopiowaniem i wklejaniem niewidocznych znaków spoza ASCII ze stron internetowych, dokumentów itp. I rozważmy „homoglify”, gdyby dwie litery lub symbole wyglądały tak samo… ale nie są.

Wreszcie, najwyraźniej możesz napotkać ten problem, jeśli spróbujesz uruchomić z pliku JAR z niepoprawnymi podpisami (META-INF/*.SF).


Alternatywne składnie dla java

Istnieją trzy alternatywne składnie do uruchamiania programów Java za pomocą java command.

1) Składnia używana do uruchamiania „wykonywalnego” pliku JAR jest następująca:

  java [ <options> ] -jar <jar-file-name> [<arg> ...]

na przykład

  java -Xmx100m -jar /usr/local/acme-example/listuser.jar fred

Nazwa klasy punktu wejścia (tj. com.acme.example.ListUser) I ścieżka klasy są określone w pliku MANIFEST pliku JAR.

2) Składnia do uruchamiania aplikacji z modułu (Java 9 i nowsze) jest następująca:

  java [ <options> ] --module <module>[/<mainclass>] [<arg> ...]

Nazwa klasy punktu wejścia jest albo zdefiniowana przez <module>siebie, albo jest podana opcjonalnie <mainclass>.

3) Począwszy od Java 11, możesz skompilować i uruchomić pojedynczy plik kodu źródłowego i uruchomić go z następującą składnią:

  java [ <options> ] <sourcefile> [<arg> ...]

gdzie jest (zazwyczaj) plik z przyrostkiem „.java”.

Aby uzyskać więcej informacji, zapoznaj się z oficjalną dokumentacją javapolecenia używanej wersji Java.


IDE

Typowe środowisko Java IDE obsługuje obsługę aplikacji Java w samej maszynie JVM IDE lub w podrzędnej maszynie JVM. Na ogół są one odporne na ten szczególny wyjątek, ponieważ IDE używa własnych mechanizmów do konstruowania ścieżki klas środowiska wykonawczego, identyfikacji głównej klasy i utworzenia javawiersza poleceń.

Jednak nadal jest możliwe wystąpienie tego wyjątku, jeśli wykonasz czynności za zapleczem IDE. Na przykład, jeśli wcześniej skonfigurowałeś program uruchamiający aplikację dla aplikacji Java w Eclipse, a następnie przeniosłeś plik JAR zawierający klasę „main” w inne miejsce w systemie plików bez informowania Eclipse , Eclipse nieświadomie uruchomiłby JVM z niepoprawną ścieżką klasy.

Krótko mówiąc, jeśli ten problem występuje w środowisku IDE, sprawdź takie rzeczy, jak nieaktualny stan IDE, uszkodzone odwołania do projektu lub uszkodzone konfiguracje programu uruchamiającego.

Możliwe jest również, że IDE po prostu się pomyli. IDE to niezwykle skomplikowane oprogramowanie składające się z wielu interaktywnych części. Wiele z tych części przyjmuje różne strategie buforowania, aby IDE jako całość reagowało. Czasami mogą się nie udać, a jednym z możliwych symptomów są problemy podczas uruchamiania aplikacji. Jeśli podejrzewasz, że tak się dzieje, warto spróbować innych rzeczy, takich jak ponowne uruchomienie IDE, przebudowa projektu i tak dalej.


Inne referencje

Stephen C.
źródło
43
Miałem ten problem, gdy próbowałem uruchomić klasę z biblioteką innej firmy. Przywołałem java w ten sposób java -cp ../third-party-library.jar com.my.package.MyClass:; to nie działa, zamiast tego należy również dodać folder lokalny do ścieżki klasy (oddzielone :, tak: to java -cp ../third-party-library.jar:. com.my.package.MyClass, to powinno działać
lanoxx
22
Po latach programowania w języku Java nadal udało mi się znaleźć na tej stronie. Dla mnie problemem było to, że składnia ścieżki klas zależy od systemu operacyjnego . Jestem trochę nowy w programowaniu w systemie Windows i nie miałem pojęcia.
keyser
5
Dodatkowe uwagi, punkt 2 uratuj mnie! Przykro mi, że javanie mówi, że nie znajduje klasy importowanej, ale klasę główną, którą próbujesz uruchomić. Jest to mylące, chociaż jestem pewien, że istnieje ku temu powód. Miałem przypadek, w którym javawiedziałem dokładnie, gdzie jest moja klasa, jednak nie mógł znaleźć jednej z zaimportowanych klas. Zamiast tego powiedzieć, że narzekał, że nie znalazł mojej głównej klasy. Naprawdę, annoing.
MSX
Miałem ten problem dwa razy w Eclipse. Pierwszy raz podpis main () był nieprawidłowy. Za drugim razem zmieniłem nazwę pliku .jar i mimo że dodałem nowy do ścieżki kompilacji, Eclipse nie znalazł starej, więc projekt nie skompilował się z tym błędem. Musiałem usunąć plik .jar z Projekt> Właściwości> Ścieżka kompilacji Java> Biblioteki.
GregT
Spotkałem to po raz trzeci. Uruchomiłem program z pliku wsadowego systemu Windows 10 i umieściłem nazwę .jar w zmiennej (wywoływanej przez „-cp% jarname%; lib *”). Przez pomyłkę umieściłem dodatkowe miejsce na końcu nazwy jar, co spowodowało błąd. Hat trick :)
GregT
239

Jeśli nazwa źródłowa to HelloWorld.java, skompilowany kod będzie HelloWorld.class.

Ten błąd pojawi się, jeśli wywołasz go za pomocą:

java HelloWorld.class

Zamiast tego użyj tego:

java HelloWorld
panoet
źródło
3
Problem polega na tym, że to rozwiązanie działa tylko dla klas Java zadeklarowanych w domyślnym pakiecie bez zależności pliku JAR. (I nawet wtedy nie zawsze). Większość programów Java nie jest taka prosta.
Stephen C
1
jak powiedział Stephen, działa to tylko z „domyślnym pakietem” - co oznacza brak deklaracji pakietu na górze pliku. W celu szybkiego przetestowania jakiegoś kodu zrobiłem: javac TestCode.javaa następniejava TestCode
Someone Somewhere
To mi nie zadziałało. Nadal mówi: „Nie można znaleźć ani załadować głównej klasy HelloWorld”
Jim
java -jar HelloWorld.jar jest również opcją
BMaximus,
12
Musiałem to zrobićjava -classpath . HelloWorld
Chris Prince,
136

Jeśli twoje klasy znajdują się w pakietach , musisz przejść cddo katalogu głównego projektu i uruchomić przy użyciu w pełni kwalifikowanej nazwy klasy (nazwa_pakietu.MainClassName).

Przykład:

Moje zajęcia są tutaj:

D:\project\com\cse\

W pełni kwalifikowana nazwa mojej głównej klasy to:

com.cse.Main

Więc cdwracam do głównego katalogu projektu:

D:\project

Następnie wydaj javapolecenie:

java com.cse.Main

Ta odpowiedź ma na celu uratowanie początkujących programistów Java przed frustracją spowodowaną powszechnym błędem. Zalecam przeczytanie przyjętej odpowiedzi, aby uzyskać bardziej szczegółową wiedzę na temat ścieżki klas języka Java.

tharinduwijewardane
źródło
2
Ta odpowiedź stanowi cały ładunek założeń. Są też inne sposoby na osiągnięcie tego. Zamiast ślepo postępować zgodnie z powyższymi wskazówkami, zaleciłbym, aby ludzie poświęcili czas na przeczytanie linków w mojej odpowiedzi, które wyjaśniają, jak działa ścieżka klas Java. Lepiej ZROZUMIEĆ, co robisz ...
Stephen C
2
Ta odpowiedź zawiera dokładne założenia, których potrzebowałem :) Byłem zlokalizowany w katalogu pliku .class i java.exe nie działał. Kiedyś cd-ed powyżej i uruchomiłem z nazwą pakietu zawartą w wierszu poleceń, zadziałało.
Nick Constantine
61

Jeśli zdefiniujesz główną klasę i główną metodę w apackage , powinieneś uruchomić ją w katalogu hierarchicznym, używając pełnej nazwy klasy ( packageName.MainClassName).

Załóżmy, że istnieje plik kodu źródłowego (Main.java):

package com.test;

public class Main {

    public static void main(String[] args) {
        System.out.println("salam 2nya\n");
    }
}

Aby uruchomić ten kod, powinieneś umieścić go Main.Classw katalogu podobnym do pakietu ./com/test/Main.Java. I użyj katalogu głównego java com.test.Main.

M-Razavi
źródło
1
Zobacz „Dodatkowe uwagi nr 1” mojej odpowiedzi. Dla lepszego wyjaśnienia tego problemu.
Stephen C
14
@StephenC Tak, twoja odpowiedź jest bardziej kompletna (i oczywiście +1), ale ta konkretna odpowiedź zawierała słowo „pakiet”, co pozwoliło mi szybko znaleźć to, czego potrzebowałem. I zadziałało. Więc +1 Razavi. StephenC, twojemu brakuje prostego przykładu pakietu, którego potrzebowałem, ponieważ jestem nowy w Javie.
kmort
5
To był dokładnie mój problem. Brnę przez mnóstwo dokumentów Java i ten konkretny przykład jest tym, czego potrzebowałem
John
1
Tak, konkretny przykład jest fajny, działał idealnie. Jestem pewien, że główna odpowiedź jest bardzo dokładna, ale trudno było zobaczyć drzewo do lasu. Nice one @Razavi
Pixel
1
Podoba mi się ta krótsza i przydatna odpowiedź zamiast zaakceptowanej!
Spara,
46

Gdy ten sam kod działa na jednym komputerze, ale pokazuje błąd na innym, najlepszym rozwiązaniem, jakie kiedykolwiek znalazłem, jest kompilacja w następujący sposób:

javac HelloWorld.java
java -cp . HelloWorld
Enamul Hassan
źródło
2
To nie jest dobra rekomendacja. Jesteś zależny od tego, czy zmienna środowiskowa CLASSPATH jest nieuzbrojona, czy też posiadasz wartość zgodną z „.”. Tak, działa w wielu przypadkach, ale w innych nie.
Stephen C
Cóż, na pewno javac -classpath . HelloWorld.javaby działało! I to jest lepsze rozwiązanie w twoim przypadku.
Stephen C
2
Jeśli masz „pakiet com.some.address” jako pierwszy wiersz - to nie zadziała. Musisz skomentować „adres paczki”.
Joe
1
@Joe - Ten hack (komentowanie pakietu) zadziała (w niektórych przypadkach), ale to zły pomysł. Lepszym pomysłem jest poznanie / zrozumienie przyczyny problemu i wdrożenie prawidłowego rozwiązania.
Stephen C
36

Pomogło mi określenie ścieżki klasy w wierszu poleceń, na przykład:

  1. Stworzyć nowy folder, C:\temp

  2. Utwórz plik Temp.java w C:\temp, zawierający następującą klasę:

    public class Temp {
        public static void main(String args[]) {
            System.out.println(args[0]);
        }
    }
  3. Otwórz wiersz polecenia w folderze C:\tempi napisz następujące polecenie, aby skompilować klasę Temp:

    javac Temp.java
  4. Uruchom skompilowaną klasę Java, dodając -classpathopcję, aby JRE wiedział, gdzie znaleźć klasę:

    java -classpath C:\temp Temp Hello!
Gwiazdy
źródło
3
W Ubuntu musiałem również określić ścieżkę. Nie rozumiem, dlaczego domyślnie nie może korzystać z bieżącego katalogu roboczego. Jestem przekonany, że Java jest sponsorowana przez producentów klawiatur !!
odszedł
1
@ gone - Powód, dla którego „.” domyślnie nie jest w zmiennej PATH, ponieważ jest to pułapka bezpieczeństwa. seas.upenn.edu/cets/answers/dot-path.html
Stephen C
Wielkie dzięki za to ...... chociaż nie jestem pewien, dlaczego java nie była w stanie znaleźć ścieżki klasy nawet po ustawieniu jej w zmiennych środowiskowych.
akash89
@ akash89 - Najbardziej prawdopodobne powody były: 1) javanie patrzył na $ CLASSPATH (ponieważ użyłeś -classpath lub -jar) lub 2) ustawienie classpath nie został ustawiony w środowisku, które nie było w rzeczywistości w kontekście faktu, że javabył biegać; np. dlatego, że nie „źródłeś” pliku, do którego dodano komendy setenv we właściwej powłoce.
Stephen C
Nadal pojawia się błąd: Nie można znaleźć lub załadować Temp klasy głównej, czy ktoś może pomóc!
Gwiazda
27

Zgodnie z komunikatem o błędzie („Nie można znaleźć lub załadować głównej klasy”) istnieją dwie kategorie problemów:

  1. Nie można znaleźć głównej klasy
  2. Nie można załadować klasy głównej (ten przypadek nie jest w pełni omówiony w zaakceptowanej odpowiedzi)

Nie można znaleźć klasy głównej, jeśli literówka lub niepoprawna składnia występuje w pełnej nazwie klasy lub nie istnieje ona w podanej ścieżce klasy .

Nie można załadować klasy głównej, gdy nie można zainicjować klasy , zazwyczaj klasa główna rozszerza inną klasę i ta klasa nie istnieje w podanej ścieżce klas.

Na przykład:

public class YourMain extends org.apache.camel.spring.Main

Jeśli nie uwzględniono sprężyny wielbłąda, ten błąd zostanie zgłoszony.

Xiao Peng - ZenUML.com
źródło
„Zasadniczo” istnieje również wiele innych kategorii. Problem braku nadklasy jest bardzo nietypową podelą. (Tak niezwykłe, że nigdy go nie widziałem ... w pytaniach zadawanych na tej stronie.)
Stephen C
Są DWA, ponieważ błąd mówi „Nie można znaleźć lub załadować głównej klasy”. Jeśli są inne kategorie, proszę o informację. Widziałem to, więc po prostu chcę się tu podzielić, może ktoś inny będzie go potrzebował.
Xiao Peng - ZenUML.com
1
Zmieniłbym to do czegoś takiego jak „Musisz uwzględnić wszystkie klasy, które są wymagane do zainicjowania klasy głównej, aby uniknąć tego konkretnego błędu”. Nie próbuję cię przekonać. To tylko sposób, który chciałbym zobaczyć. Zostawiłem tutaj odpowiedź tylko dla osób, które mogą lubić czytać w ten sposób. Nie przedłużajmy tej dyskusji :) Zmieniłem moje zdanie na „nie do końca omówione w przyjętej odpowiedzi” i mam nadzieję, że poczujesz się lepiej.
Xiao Peng - ZenUML.com 17.09.15
5
Ta informacja jest kluczowa i zasługuje na wyraźną wzmiankę (to jedyna wspomniana odpowiedź extends). Właśnie nauczyłem się na własnej skórze, że gdy klasa główna nie ładuje się, ponieważ rozszerza inną, której nie można znaleźć , java nie zgłasza, która klasa nie została znaleziona (w przeciwieństwie do NoClassDefFoundError). Tak, tak się dzieje, a kiedy się o tym nie wie, jest to sytuacja ciągnąca za włosy.
Hugues M.
1
Czy w tej sytuacji można dokładnie powiedzieć, która klasa zależności nie ładuje się?
Carlos A. Ibarra
16

Miałem taki błąd w tym przypadku:

java -cp lib.jar com.mypackage.Main

Działa z ;systemami Windows i :Unix:

java -cp lib.jar; com.mypackage.Main
Yamahar1sp
źródło
Tak. Najprawdopodobniej Mainnie ma go w pliku JAR. -cp lib.jar;oznacza to samo co -cp lib.jar;. np. bieżący katalog jest zawarty w ścieżce klasy.
Stephen C
W końcu naprawiono problem z unixem. Dzięki (działa z :)
Vicky
16

Spróbuj -Xdiag .

Odpowiedź Steve'a C ładnie obejmuje możliwe przypadki, ale czasem ustalenie, czy nie można znaleźć lub załadować klasy, może nie być takie proste. Użyj java -Xdiag(od JDK 7). Wyświetla to ładny ślad stosu, który daje podpowiedź do tego, co Could not find or load main classoznacza komunikat.

Może na przykład wskazywać inne klasy używane przez klasę główną, których nie można znaleźć, i uniemożliwił załadowanie klasy głównej.

jan.supol
źródło
16

Użyj tego polecenia:

java -cp . [PACKAGE.]CLASSNAME

Przykład: jeśli twoja nazwa klasy to Hello.class utworzona z Hello.java, użyj następującego polecenia:

java -cp . Hello

Jeśli plik Hello.java znajduje się w pakiecie com.demo, użyj poniższej komendy

java -cp . com.demo.Hello

Z JDK 8 wiele razy zdarza się, że plik klasy znajduje się w tym samym folderze, ale javapolecenie oczekuje ścieżki klasy i dlatego dodajemy, -cp .aby wziąć bieżący folder jako odniesienie do ścieżki klasy.

shaILU
źródło
Działa to tylko w prostych przypadkach. Bardziej skomplikowane przypadki wymagają bardziej skomplikowanej ścieżki klas.
Stephen C
A dla >> naprawdę << prostych przypadków, nie -cp .jest konieczne, ponieważ jeśli nie $CLASSPATHjest ustawione, to .jest domyślna ścieżka klasy.
Stephen C
Nie Stephen, wiele razy w domyślnej ścieżce klas systemu Windows nie działa. Wypróbowałem to na trzech różnych maszynach, możesz też tego wypróbować.
shaILU
Prawdopodobnie dlatego, że gdzieś ustawiłeś zmienną środowiskową% CLASSPATH%. Jeśli to zrobisz, nie będziesz używać domyślnej ścieżki klasy. (Co daje echo %CLASSPATH%wynik?) I nie, nie mogę sprawdzić, ponieważ nie mam komputera z systemem Windows.
Stephen C
2
Działa
15

Czasami to, co może być przyczyną problemu, nie ma nic wspólnego z klasą główną i musiałem to znaleźć na własnej skórze. To była biblioteka, do której się odwołałem, którą przeniosłam i dała mi:

Nie można znaleźć lub załadować głównej klasy xxx Linux

Właśnie usunąłem to odniesienie, dodałem je ponownie i znów zadziałało.

Eduardo Dennis
źródło
1
Wygląda na to, że problem polegał na tym, że miałeś niepoprawną ścieżkę klasy z powodu zepsutego „odwołania” w swoim projekcie w twoim IDE. Zaktualizuję moją odpowiedź, aby uwzględnić tę sprawę.
Stephen C,
@StephenC i EduardoDennis, to tutaj także brakowało słoika, który zawierał interfejs, od którego zależała główna instancja. Komunikat o błędzie jest więc zbyt szeroki. Powinienem powiedzieć „nie można znaleźć”, jeśli nie znaleziono pliku klasy i „nie można załadować (brakujących zależności)”, jeśli brakuje czegoś innego, ale nie samego pliku, więc zbyt szeroki komunikat o błędzie jest mylący, jeśli skupisz się tylko w części „znajdź” :(
Aquarius Power
@AquariusPower - Powinien istnieć dodatkowy „spowodowany przez” stacktrace dla wyjątku „przyczyna”, w którym brakowało klasy wht. Jeśli chcesz zasugerować programistom Java, że ​​zmieniają komunikat o błędzie, który mówi, że od ponad 20 lat ... nie krępuj się. (Myślę, że komunikat o błędzie jest poprawny. Problem polegał na tym, że >> zawęziłeś niewłaściwą klauzulę.)
Stephen C
@StephenC miałem na myśli, że z pewnością mają dostęp do informacji, jeśli główny plik klasy jest dostępny, czy nie, więc dlaczego nie pokazać nam lepszego komunikatu o błędzie informującego o braku takiego pliku. Z drugiej strony mogliby również powiedzieć „Plik został znaleziony, ale nie można go załadować”. Natychmiast skupilibyśmy się na zależnościach, zamiast tracić pół dnia na badanie i testowanie rzeczy do zrozumienia. Właśnie to miałem na myśli :). Mogą to robić w ograniczony sposób przez ponad 20 lat, ale mogą to poprawić, a my jesteśmy tutaj, aby to zapewnić dzięki naszej krytyce i skargom! : D
Aquarius Power
Proszę zrozumieć, co >> I << znaczyło. Narzekanie na to w jakimś niejasnym komentarzu do 3-letnich pytań i odpowiedzi nic nie da. Ludzie, którzy mogą podejrzewać twoje skargi, nie zauważą tego. Jeśli chcesz zrobić coś konstruktywnego, prześlij łatkę. (Nie oceniam twoich szans, ale będą one większe niż gdybyś po prostu narzekał na to.)
Stephen C
10

W tym przypadku masz:

Nie można znaleźć lub załadować głównej klasy ? Classpath

Jest tak, ponieważ używasz „-classpath”, ale myślnik nie jest tym samym myślnikiem, którego używasz javaw wierszu polecenia. Miałem problem z kopiowaniem i wklejaniem z Notatnika na cmd.

Nathan Williams
źródło
2
Łał! To całkowicie dziwna przyczyna! (Ale służy ci to do używania Notatnika zamiast prawdziwego edytora tekstu :-))
Stephen C
10

Miałem ten sam problem i w końcu znalazłem swój błąd :) Użyłem tego polecenia do kompilacji i działało poprawnie:

javac -cp "/home/omidmohebbi/AAAATest/jars/core-1.7.jar:/home/omidmohebbi/AAAATest/jars/javase-1.7.jar:/home/omidmohebbi/AAAATest/jars/qrgen-1.2.jar" qrcode.java

Ale to polecenie nie działało dla mnie (nie mogłem znaleźć ani załadować głównej klasy qrcode):

java -cp "/home/omidmohebbi/AAAATest/jars/core-1.7.jar:/home/omidmohebbi/AAAATest/jars/javase-1.7.jar:/home/omidmohebbi/AAAATest/jars/qrgen-1.2.jar" qrcode

W końcu właśnie dodałem znak „:” na końcu ścieżki klas i problem został rozwiązany:

java -cp "/home/omidmohebbi/AAAATest/jars/core-1.7.jar:/home/omidmohebbi/AAAATest/jars/javase-1.7.jar:/home/omidmohebbi/AAAATest/jars/qrgen-1.2.jar:" qrcode
Omid Mohebbi
źródło
7

W moim przypadku wystąpił błąd, ponieważ podałem nazwę pliku źródłowego zamiast nazwy klasy.

Musimy podać interpreterowi nazwę klasy zawierającą główną metodę.

KawaiKx
źródło
Tak. Zobacz mój przykład # 2 niewłaściwych sposobów określenia nazwy klasy !!
Stephen C
7

Może ci to pomóc, jeśli twoja sprawa jest dokładnie taka jak moja: jako początkujący napotkałem również ten problem, gdy próbowałem uruchomić program Java.

Skompilowałem to w następujący sposób:

javac HelloWorld.java

Próbowałem też uruchomić to samo rozszerzenie:

java Helloworld.java

Kiedy usunąłem .javai przepisałem polecenie jak java HelloWorld, program działał idealnie. :)

Ramesh Pareek
źródło
2
Wynika to z faktu, że uruchamiasz skompilowaną wersję .java. W rzeczywistości wykonuje plik .class
Jason V
Dla przypomnienia, jest to to samo, co powód nr 1, przykład nr 5 w mojej odpowiedzi ...
Stephen C
6

Wszystkie odpowiedzi tutaj są skierowane do użytkowników systemu Windows. W przypadku komputerów Mac separator ścieżki klas :nie jest ;. Ponieważ błąd ustawiania używania ścieżki klasy ;nie jest generowany, może to być trudne do wykrycia, jeśli pochodzi z systemu Windows na komputer Mac.

Oto odpowiednie polecenie Maca:

java -classpath ".:./lib/*" com.test.MyClass

Gdzie w tym przykładzie jest paczka com.testi libfolder ma być również dołączony do ścieżki klasy.

niebieskie niebo
źródło
2
W systemie Linux, podobnie jak w systemie Mac.
Alex78191,
Dlaczego /*jest to konieczne?
Alex78191,
Jest to składnia wieloznaczna. (Nie jest to obowiązkowe. Możesz jawnie wymienić pliki JAR, jeśli chcesz.)
Stephen C
6

wprowadź opis zdjęcia tutaj

Lokalizacja pliku klasy: C: \ test \ com \ company

Nazwa pliku: Main.class

W pełni kwalifikowana nazwa klasy: com.company.Main

Polecenie z wiersza poleceń:

java  -classpath "C:\test" com.company.Main

Zauważ, że ścieżka klasy NIE zawiera \ com \ company

developer747
źródło
6

Sporo czasu poświęciłem na rozwiązanie tego problemu. Myślałem, że w jakiś sposób nieprawidłowo ustawiłem ścieżkę klasy, ale problem polegał na tym, że wpisałem:

java -cp C:/java/MyClasses C:/java/MyClasses/utilities/myapp/Cool  

zamiast:

java -cp C:/java/MyClasses utilities/myapp/Cool   

Pomyślałem, że znaczenie w pełni kwalifikowane ma obejmować pełną nazwę ścieżki zamiast pełnej nazwy pakietu.

mathewbruens
źródło
Zaktualizowałem swoją odpowiedź, aby spróbować rozwiązać ten problem.
Stephen C
2
Żadne z tych nie jest poprawne. Klasa musi być podana jako, utilities.myapp.Coollub jakakolwiek jest nazwa pakietu, jeśli istnieje.
user207421,
5

Najpierw ustaw ścieżkę za pomocą tego polecenia;

set path="paste the set path address"

Następnie musisz załadować program. Wpisz „cd (nazwa folderu)” na zapisanym dysku i skompiluj go. Na przykład, jeśli mój program jest zapisany na dysku D, wpisz „D:” naciśnij enter i wpisz „cd (nazwa folderu)”.

bieg
źródło
4
To nie pomaga. To pytanie dotyczy programów Java, a nie zwykłych plików wykonywalnych. Java nie używa PATH do lokalizowania czegokolwiek, a jeśli „cd” pomaga, to raczej przez szczęście niż przez osąd.
Stephen C,
if "cd" helps then it by luck rather than by judgement. To źle (jak sądzę), ponieważ Java .domyślnie używa bieżącego katalogu jako części ścieżki klas.
GKFX
2
@GKFX - o to mi chodzi. O ile nie wiesz, że używasz domyślnej ścieżki klasy (lub ścieżki klasy z „.”), „Cd” nie przyniesie żadnego efektu. To rozwiązanie działa bardziej na szczęście (tj. Zgadując / mając nadzieję, że „.” Znajduje się na ścieżce klasy) niż na podstawie osądu (tj. Sprawdzając, że „.” Znajduje się na ścieżce klasy). Ponadto nie masz racji co do wartości domyślnej. Java używa „.” domyślnie jako ścieżka klasy, a nie jako część ścieżki klasy.
Stephen C
5

Tym, co naprawiło problem w moim przypadku, było:

Kliknij prawym przyciskiem myszy projekt / klasę, którą chcesz uruchomić, a następnie Run As-> Run Configurations. Następnie należy naprawić istniejącą konfigurację lub dodać nową w następujący sposób:

otwórz Classpathkartę, kliknij Advanced...przycisk, a następnie dodaj binfolder swojego projektu.

syntagma
źródło
5

Jeśli używasz Maven do zbudowania pliku JAR, upewnij się, że określiłeś klasę główną w pliku pom.xml:

<build>
    <plugins>
        <plugin>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>class name us.com.test.abc.MyMainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>
Junchen Liu
źródło
4

Jest to szczególny przypadek, ale ponieważ wszedłem na tę stronę w poszukiwaniu rozwiązania i nie znalazłem go, dodam go tutaj.

Windows (testowany z 7) nie akceptuje znaków specjalnych (np á ) w nazwach klas i pakietów. Linux tak.

Dowiedziałem się tego, gdy zbudowałem .jarNetBeans i próbowałem uruchomić go w wierszu poleceń. Działał w NetBeans, ale nie w wierszu poleceń.

GuiRitter
źródło
4

W systemie Windows .;na początku ustaw wartość CLASSPATH.

The. (kropka) oznacza „zajrzyj do bieżącego katalogu”. To jest trwałe rozwiązanie.

Możesz także ustawić „jednorazowo” za pomocą zestawu CLASSPATH=%CLASSPATH%;.. Trwa to tak długo, jak długo okno cmd jest otwarte.

Nenad Bulatovic
źródło
1
Ta rada może, ale nie musi, pomóc. Pomoże, jeśli drzewo klas zawierające klasy w bieżącym katalogu. Nie zrobi tego, jeśli nie są. Nie zrobiłbym tego. Zamiast tego stworzyłbym skrypt opakowujący jednowierszowy, który działałby niezależnie od tego, czy użytkownik jest w katalogu „właściwym”.
Stephen C
4

Naprawdę musisz to zrobić z srcfolderu. Tam wpisz następujący wiersz polecenia:

[name of the package].[Class Name] [arguments]

Powiedzmy, że twoja klasa jest wywoływana CommandLine.class, a kod wygląda następująco:

package com.tutorialspoint.java;

    /**
     * Created by mda21185 on 15-6-2016.
     */

    public class CommandLine {
        public static void main(String args[]){
            for(int i=0; i<args.length; i++){
                System.out.println("args[" + i + "]: " + args[i]);
            }
        }
    }

Następnie powinieneś cdprzejść do folderu src, a polecenie, które musisz uruchomić, wyglądałoby tak:

java com.tutorialspoint.java.CommandLine this is a command line 200 -100

Dane wyjściowe w wierszu poleceń będą następujące:

args[0]: this
args[1]: is
args[2]: a
args[3]: command
args[4]: line
args[5]: 200
args[6]: -100
Mikrofon. re
źródło
2
Klasy nie można nazwać „CommandLine.class”. Byłby to błąd składniowy Java. (Masz na myśli to, że plik zawierający skompilowaną klasę nazywa się „CommandLine.class” ...). Innym problemem jest to, że twoja instrukcja „cd do katalogu źródłowego” działa tylko wtedy, gdy skompilowałeś kod >> do << drzewa katalogu źródłowego. Na koniec, jeśli twój kompilator użył argumentu „-cp”, to potrzebujesz odpowiednika podczas uruchamiania.
Stephen C
W moim projekcie mam folder src i folder bin w katalogu głównym. Musiałem cdsię src, a następnie uruchomić komendę java ../bin com.blah.blah.MyClassktóry pracował dla mnie. Dziękuję za podpowiedź!
tamj0rd2
3

W Javie, gdy czasami uruchamiasz JVM z wiersza poleceń za pomocą pliku wykonywalnego java i próbujesz uruchomić program z pliku klasy z publicznym statycznym void main (PSVM), możesz napotkać poniższy błąd, mimo że parametr classpath to JVM jest dokładny, a plik klasy jest obecny w ścieżce klasy:

Error: main class not found or loaded

Dzieje się tak, jeśli nie można załadować pliku klasy z PSVM. Jednym z możliwych powodów jest to, że klasa może implementować interfejs lub rozszerzać inną klasę, która nie znajduje się w ścieżce klas. Zwykle, jeśli klasa nie znajduje się w ścieżce klasy, zgłoszony błąd wskazuje jako taki. Ale jeśli używana klasa zostanie rozszerzona lub zaimplementowana, java nie będzie mogła załadować samej klasy.

Odniesienie: https://www.computingnotes.net/java/error-main-class-not-found-or-loaded/

Anandaraja Ravi
źródło
1
Czy przeczytałeś zaakceptowaną odpowiedź? Czy twoja odpowiedź dodaje coś nowego?
Stephen C
1
@StephenC Próbowałem znaleźć powód na twojej liście, patrząc na kategorie „Powód” i ich punkty. Nie mogłem znaleźć pasującego tytułu w tytule „Powód nr 1” i „Powód nr 2” nie wyglądały tak blisko mojej sprawy (ponieważ byłem pewien, że nie ma problemu z samą ścieżką klasy). Znalazłem przyczynę, przeprowadzając eksperymenty i byłem zaskoczony, że w moim przypadku pojawił się błąd „nie znaleziono głównej klasy”, ponieważ interfejs implementacji nie znajdował się na ścieżce klasy. Jasne, że możesz powiedzieć „powinieneś przeczytać wszystko opisane w poście”, ale wydaje mi się, że Twoja lista przyczyn może zostać ulepszona.
gumkins
3

Podczas uruchamiania javaz -cpopcją opisaną w Windows PowerShell może pojawić się błąd, który wygląda mniej więcej tak:

The term `ClassName` is not recognized as the name of a cmdlet, function, script ...

Aby program PowerShell mógł zaakceptować polecenie, argumenty -cpopcji muszą być zawarte w cudzysłowach, jak w:

java -cp 'someDependency.jar;.' ClassName

Formowanie polecenia w ten sposób powinno pozwolić Java poprawnie przetwarzać argumenty ścieżki klasy.

Chezzwizz
źródło
3

Napotkałem również podobne błędy podczas testowania połączenia JDBC Java MongoDB. Myślę, że dobrze jest streścić moje ostateczne rozwiązanie w skrócie, aby w przyszłości każdy mógł bezpośrednio przyjrzeć się dwóm poleceniom i kontynuować.

Załóżmy, że znajdujesz się w katalogu, w którym istnieje plik Java i zależności zewnętrzne (pliki JAR).

Skompilować:

javac -cp mongo-java-driver-3.4.1.jar JavaMongoDBConnection.java
  • -cp - argument ścieżki klasy; przekaż wszystkie zależne pliki JAR jeden po drugim
  • * .java - jest to plik klasy Java, który ma główną metodę. sdsd

Biegać:

java -cp mongo-java-driver-3.4.1.jar: JavaMongoDBConnection
  • Proszę zwrócić uwagę na dwukropek (Unix) / przecinek (Windows) po zakończeniu wszystkich plików JAR zależności
  • Na koniec obserwuj nazwę klasy głównej bez żadnego rozszerzenia (bez .class lub .java)
khichar.anil
źródło
To wszystko zakłada, że ​​1) JavaMongoDBConnectionnie ma pakietu i 2) nie zmieniasz katalogu. Jest to, delikatnie mówiąc, kruche. Nie wyjaśniając problemów, sprawi, że nowicjusze wypróbują to podejście w sytuacjach, w których nie będzie działać . Krótko mówiąc, zachęca do „technik programowania voodoo”: en.wikipedia.org/wiki/Voodoo_programming
Stephen C
3

W porządku, jest już wiele odpowiedzi, ale nikt nie wspomniał o przypadku, w którym winowajcą mogą być uprawnienia do plików.

Podczas działania użytkownik może nie mieć dostępu do pliku JAR lub jednego z katalogów ścieżki. Rozważ na przykład:

Plik jar w /dir1/dir2/dir3/myjar.jar

Użytkownik 1, który jest właścicielem pliku JAR, może:

# Running as User1
cd /dir1/dir2/dir3/
chmod +r myjar.jar

Ale nadal nie działa:

# Running as User2
java -cp "/dir1/dir2/dir3:/dir1/dir2/javalibs" MyProgram
Error: Could not find or load main class MyProgram

Jest tak, ponieważ działający użytkownik (Użytkownik2) nie ma dostępu do katalogu 1, katalogu 2 lub javalibs lub katalogu 3. Może doprowadzić kogoś do szału, gdy Użytkownik1 może zobaczyć pliki i uzyskać do nich dostęp, ale błąd nadal występuje dla Użytkownika2.

biocyberman
źródło
2

Wystąpił ten błąd po zrobieniu mvn eclipse:eclipse To .classpathtrochę popsuło mój plik.

Musiałem zmienić linie .classpathz

<classpathentry kind="src" path="src/main/java" including="**/*.java"/>
<classpathentry kind="src" path="src/main/resources" excluding="**/*.java"/>

do

<classpathentry kind="src" path="src/main/java" output="target/classes" />
<classpathentry kind="src" path="src/main/resources" excluding="**"  output="target/classes" />
Jaanus
źródło
2

Nie udało mi się rozwiązać tego problemu za pomocą podanych tutaj rozwiązań (chociaż podana odpowiedź niewątpliwie oczyściła moje koncepcje). Napotkałem ten problem dwa razy i za każdym razem próbowałem różnych rozwiązań (w środowisku Eclipse IDE).

  • Po pierwsze, spotkałem się z wieloma mainmetodami w różnych klasach mojego projektu. Usunąłem więc mainmetodę z kolejnych klas.
  • Po drugie, wypróbowałem następujące rozwiązanie:
    1. Kliknij prawym przyciskiem myszy mój główny katalog projektu.
    2. Udaj się do źródła, a następnie posprzątaj i pozostań przy ustawieniach domyślnych i po zakończeniu. Po kilku zadaniach w tle zostaniesz przekierowany do głównego katalogu projektu.
    3. Następnie zamykam projekt, otwieram go ponownie i bum, w końcu rozwiązałem swój problem.
Anus Kaleem
źródło
1
Usunięcie mainmetod nie rozwiąże problemu. Nie ma nic technicznie złego w aplikacji, która ma wiele punktów wejścia.
Stephen C