Was bedeutet "Could not find or load main class"?

Ein häufiges Problem, mit dem neue Java-Entwickler konfrontiert werden, besteht darin, dass ihre Programme mit der Fehlermeldung nicht ausgeführt werden können: Konnte die Hauptklasse nicht finden oder laden ...

Was bedeutet das, was ist die Ursache und wie kann man das Problem beheben?

Lösung

Die Syntax des Befehls java

Zunächst müssen Sie verstehen, wie man ein Programm mit dem Befehl java (oder javaw) korrekt startet. Die normale Syntax1 ist diese:

    java [  ... ]  [ ...]

wobei eine Kommandozeilenoption ist (beginnend mit einem "-" Zeichen), ein voll qualifizierter Java-Klassenname ist und `` ein beliebiges Kommandozeilenargument ist, das an Ihre Anwendung übergeben wird.
1 - Es gibt eine zweite Syntax für "ausführbare" JAR-Dateien, die ich unten beschreiben werde. Der vollqualifizierte Name (FQN) für die Klasse wird üblicherweise so geschrieben, wie man es im Java-Quellcode tun würde; z.B.

    packagename.packagename2.packagename3.ClassName

Einige Versionen des java-Befehls erlauben jedoch die Verwendung von Schrägstrichen anstelle von Punkten, z.B.

    packagename/packagename2/packagename3/ClassName

was (verwirrenderweise) wie ein Dateipfadname aussieht, aber keiner ist. Beachten Sie, dass der Begriff voll qualifizierter Name Standard-Java-Terminologie ist ... nicht etwas, das ich mir nur ausgedacht habe, um Sie zu verwirren :-) Hier ist ein Beispiel dafür, wie ein java-Befehl aussehen sollte:

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

Der obige Befehl veranlasst den java-Befehl, folgendes zu tun:

  1. Suche nach der kompilierten Version der Klasse "com.acme.example.ListUsers".
  2. Laden Sie die Klasse.
  3. Prüfen Sie, ob die Klasse eine main Methode mit Signatur, Rückgabetyp und Modifikatoren hat, die durch public static void main(String[]) angegeben werden. (Beachten Sie, dass der Name des Methodenarguments NICHT Teil der Signatur ist).
  4. Rufen Sie diese Methode auf und übergeben Sie ihr die Befehlszeilenargumente ("fred", "joe", "bert") als String[]. Gründe, warum Java die Klasse nicht finden kann

    Wenn Sie die Meldung "Could not find or load main class ..." erhalten, bedeutet das, dass der erste Schritt fehlgeschlagen ist. Der Befehl java war nicht in der Lage, die Klasse zu finden. Und tatsächlich ist das "..." in der Meldung der voll qualifizierte Klassenname, nach dem java sucht. Warum also kann die Klasse nicht gefunden werden?
    Grund #1 - Sie haben einen Fehler mit dem classname-Argument gemacht

    Die erste wahrscheinliche Ursache ist, dass Sie den falschen Klassennamen angegeben haben. (Oder ... den richtigen Klassennamen, aber in der falschen Form.) In Anbetracht des obigen Beispiels gibt es eine Reihe von falschen Möglichkeiten, den Klassennamen anzugeben:

  • Beispiel #1 - ein einfacher Klassenname:

    java ListUser

    Wenn die Klasse in einem Paket wie com.acme.example deklariert ist, dann müssen Sie den vollständigen Klassennamen einschließlich des Paketnamens im java-Befehl verwenden; z.B. java com.acme.example.ListUser

  • Beispiel #2 - ein Dateiname oder Pfadname anstelle eines Klassennamens: java ListUser.class java com/acme/example/ListUser.class

  • Beispiel Nr. 3 - ein Klassenname mit falscher Schreibweise: java com.acme.example.listuser

  • Beispiel #4 - ein Tippfehler java com.acme.example.mistuser

  • Beispiel #5 - ein Quelldateiname java ListUser.java

  • Beispiel #6 - Sie haben den Klassennamen komplett vergessen java viele Argumente Grund #2 - der Klassenpfad der Anwendung ist falsch angegeben

    Die zweite wahrscheinliche Ursache ist, dass der Klassenname korrekt ist, aber der Befehl java die Klasse nicht finden kann. Um dies zu verstehen, müssen Sie das Konzept des "Klassenpfads" verstehen. Dies wird in der Oracle-Dokumentation gut erklärt:

  • The java command documentation

  • Einstellung des Klassenpfads.

  • Das Java-Tutorial - PATH und CLASSPATH Also ... wenn Sie den Klassennamen korrekt angegeben haben, müssen Sie als Nächstes prüfen, ob Sie den Klassenpfad korrekt angegeben haben:

  1. Lesen Sie die drei oben verlinkten Dokumente. (Ja ... LESEN Sie sie. Es ist wichtig, dass ein Java-Programmierer zumindest die Grundlagen der Funktionsweise des Java-Klassenpfads versteht).
  2. Schauen Sie sich die Kommandozeile und / oder die Umgebungsvariable CLASSPATH an, die in Kraft ist, wenn Sie den Befehl java ausführen. Überprüfen Sie, ob die Namen der Verzeichnisse und JAR-Dateien korrekt sind.
  3. Wenn es relative Pfadnamen im Klassenpfad gibt, prüfen Sie, ob sie korrekt aufgelöst werden ... von dem aktuellen Verzeichnis, das beim Ausführen des java-Befehls in Kraft ist.
  4. Prüfen Sie, ob die (in der Fehlermeldung erwähnte) Klasse im effektiven Klassenpfad gefunden werden kann.
  5. Beachten Sie, dass die Klassenpfad-Syntax für Windows unterschiedlich ist im Vergleich zu Linux und Mac OS. (Der Klassenpfad-Trenner ist ; unter Windows und : unter den anderen. Wenn Sie das falsche Trennzeichen für Ihre Plattform verwenden, werden Sie keine explizite Fehlermeldung erhalten. Stattdessen erhalten Sie eine nicht existierende Datei oder ein nicht existierendes Verzeichnis im Pfad, das stillschweigend ignoriert wird). Grund #2a - das falsche Verzeichnis befindet sich auf dem Klassenpfad

    Wenn Sie ein Verzeichnis auf den Klassenpfad setzen, entspricht es fiktiv der Wurzel des qualifizierten Namensraums. Die Klassen befinden sich in der Verzeichnisstruktur unterhalb dieser Wurzel, durch Abbildung des voll qualifizierten Namens auf einen Pfadnamen. Wenn beispielsweise "/usr/local/acme/classes" im Klassenpfad liegt, sucht die JVM bei der Suche nach einer Klasse namens com.acme.example.Foon nach einer ".class" Datei mit diesem Pfadnamen:

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

Wenn Sie "/usr/local/acme/classes/com/acme/example" auf den Klassenpfad gesetzt hätten, dann könnte die JVM die Klasse nicht finden. Grund #2b - der Pfad des Unterverzeichnisses stimmt nicht mit dem FQN überein

Wenn der FQN Ihrer Klasse com.acme.example.Foon lautet, dann sucht die JVM nach "Foon.class" im Verzeichnis "com/acme/example":

  • Wenn Ihre Verzeichnisstruktur nicht mit der Paketbenennung nach dem obigen Muster übereinstimmt, wird die JVM Ihre Klasse nicht finden.
  • Wenn Sie versuchen, eine Klasse umzubenennen, indem Sie sie verschieben, wird auch das fehlschlagen ... aber der Exception-Stacktrace wird anders aussehen. Er könnte etwa so lauten: Caused by: java.lang.NoClassDefFoundError: <path> (falscher Name: ) weil die FQN in der Klassendatei nicht mit dem übereinstimmt, was der Klassenlader zu finden erwartet. Um ein konkretes Beispiel zu geben, nehmen wir an, dass:
  • Sie wollen die Klasse "com.acme.example.Foon" ausführen,
  • der vollständige Dateipfad lautet /usr/local/acme/classes/com/acme/example/Foon.class,
  • Ihr aktuelles Arbeitsverzeichnis ist /usr/local/acme/classes/com/acme/example/, dann:
# 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

Hinweise:

  • Die Option -classpath kann in den meisten Java-Versionen zu -cp abgekürzt werden. Prüfen Sie die entsprechenden Handbucheinträge für java, javac und so weiter.

  • Überlegen Sie sorgfältig, wenn Sie zwischen absoluten und relativen Pfadnamen in Klassenpfaden wählen. Denken Sie daran, dass ein relativer Pfadname "brechen" kann, wenn sich das aktuelle Verzeichnis ändert.
    Grund #2c - fehlende Abhängigkeiten im Klassenpfad

    Der Klassenpfad muss alle anderen (Nicht-System) Klassen enthalten, von denen Ihre Anwendung abhängt. (Die Systemklassen werden automatisch gefunden, und Sie müssen sich selten darum kümmern). Damit die Hauptklasse korrekt geladen werden kann, muss die JVM diese finden:

  • die Klasse selbst.

  • alle Klassen und Schnittstellen in der Oberklassenhierarchie (siehe z.B. https://stackoverflow.com/questions/42880748)

  • alle Klassen und Schnittstellen, auf die mit Hilfe von Variablen oder Variablendeklarationen, Methodenaufrufen oder Feldzugriffsausdrücken verwiesen wird. (Hinweis: Die JLS- und JVM-Spezifikationen lassen der JVM einen gewissen Spielraum, um Klassen "lazily" zu laden, und dies kann sich darauf auswirken, wann eine Classloader-Exception ausgelöst wird). Grund #3 - die Klasse wurde im falschen Paket deklariert

    Es kommt gelegentlich vor, dass jemand eine Quellcodedatei in den falschen Ordner in ihrem Quellcode-Baum ablegt oder die Paket-Deklaration auslässt. Wenn Sie dies in einer IDE tun, wird der IDE-Compiler Sie sofort darauf hinweisen. Wenn Sie ein anständiges Java-Build-Tool verwenden, wird das Tool javac so ausführen, dass das Problem erkannt wird. Wenn Sie jedoch Ihren Java-Code von Hand erstellen, können Sie dies so tun, dass der Compiler das Problem nicht bemerkt und die resultierende ".class" Datei nicht an der Stelle ist, an der Sie sie erwarten. Sie können das Problem immer noch nicht finden?

    Es gibt viele Dinge zu überprüfen, und es ist leicht, etwas zu übersehen. Versuchen Sie, die Option -Xdiag in die java-Befehlszeile einzufügen (als erstes nach java). Sie gibt verschiedene Informationen über das Laden von Klassen aus, die Ihnen Hinweise auf das eigentliche Problem geben können. Ziehen Sie auch mögliche Probleme in Betracht, die durch Kopieren und Einfügen von unsichtbaren oder Nicht-ASCII-Zeichen aus Websites, Dokumenten usw. verursacht werden. Und denken Sie an "Homoglyphen", wo zwei Buchstaben oder Symbole gleich aussehen ... aber es nicht sind'.

    Die Syntax "java -jar `

    Die alternative Syntax, die für "ausführbare" JAR-Dateien verwendet wird, lautet wie folgt:

  java [  ... ] -jar  [ ...]

z.B..

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

In diesem Fall werden der Name der Einstiegsklasse (z.B. com.acme.example.ListUser) und der Klassenpfad im MANIFEST der JAR-Datei angegeben.

IDEs

Eine typische Java-IDE bietet Unterstützung für die Ausführung von Java-Anwendungen in der IDE-JVM selbst oder in einer untergeordneten JVM. Diese sind generell immun gegen diese spezielle Ausnahme, weil die IDE ihre eigenen Mechanismen verwendet, um den Laufzeit-Klassenpfad zu konstruieren, die Hauptklasse zu identifizieren und die java-Befehlszeile zu erstellen. Es ist jedoch immer noch möglich, dass diese Ausnahme auftritt, wenn Sie Dinge hinter dem Rücken der IDE tun. Wenn Sie beispielsweise zuvor einen Application Launcher für Ihre Java-Anwendung in Eclipse eingerichtet haben und dann die JAR-Datei mit der Klasse "main" an einen anderen Ort im Dateisystem verschoben haben, ohne dies Eclipse mitzuteilen, würde Eclipse unwissentlich die JVM mit einem falschen Klassenpfad starten. Kurz gesagt, wenn Sie dieses Problem in einer IDE haben, suchen Sie nach Dingen wie einem veralteten IDE-Status, fehlerhaften Projektreferenzen oder fehlerhaften Konfigurationen des Launchers. Es ist auch möglich, dass eine IDE einfach durcheinander kommt. IDE's sind äußerst komplizierte Software, die aus vielen interagierenden Teilen besteht. Viele dieser Teile verwenden verschiedene Caching-Strategien, um die IDE als Ganzes reaktionsfähig zu machen. Diese können manchmal schief gehen, und ein mögliches Symptom sind Probleme beim Starten von Anwendungen. Wenn Sie vermuten, dass dies der Fall sein könnte, lohnt es sich, die IDE neu zu starten und das Projekt neu zu erstellen.

Andere Referenzen

Kommentare (11)

Manchmal hat die Ursache des Problems nichts mit der Hauptklasse zu tun, und das musste ich auf die harte Tour herausfinden. Es war eine referenzierte Bibliothek, die ich verschoben habe, und es gab mir die:

Konnte die Hauptklasse xxx Linux nicht finden oder laden

Ich löschte den Verweis, fügte ihn wieder hinzu, und es funktionierte wieder.

Kommentare (5)

Legen Sie zunächst den Pfad mit diesem Befehl fest;

set path="paste the set path address"

Dann müssen Sie das Programm laden. Geben Sie "cd (Ordnername)" in das gespeicherte Laufwerk ein und kompilieren Sie es. Zum Beispiel, wenn mein Programm auf dem Laufwerk D gespeichert ist, geben Sie "D:" ein; drücken Sie die Eingabetaste und geben Sie " cd (Ordnername)" ein.

Kommentare (3)