Wat betekent "Could not find or load main class"?
Een veel voorkomend probleem dat nieuwe Java ontwikkelaars ondervinden is dat hun programma's niet lopen met de foutmelding: Kan hoofdklasse niet vinden of laden ...
Wat betekent dit, wat veroorzaakt het, en hoe moet je het oplossen?
1270
3
De
java
commando syntaxisAllereerst moet je de juiste manier begrijpen om een programma te starten met het
java
(ofjavaw
) commando. De normale syntaxis1 is deze:waarbij
een command line optie is (beginnend met een "-" karakter),
een volledig gekwalificeerde Java class naam is, en `` een willekeurig command line argument is dat wordt doorgegeven aan je applicatie.1 - Er is een tweede syntax voor "executable" JAR files die ik onderaan zal beschrijven. De volledig gekwalificeerde naam (FQN) voor de klasse wordt conventioneel geschreven zoals je zou doen in Java broncode; bv.
Sommige versies van het
java
commando staan je echter toe om schuine strepen te gebruiken in plaats van punten; bijv.wat (verwarrend genoeg) lijkt op een bestandspadnaam, maar het niet is. Merk op dat de term fully qualified name standaard Java terminologie is ... niet iets dat ik verzon om je in verwarring te brengen :-) Hier is een voorbeeld van hoe een
java
commando eruit zou moeten zien:Het bovenstaande zal ervoor zorgen dat het
java
commando het volgende doet:com.acme.example.ListUsers
class.main
methode heeft met signature, return type en modifiers gegeven doorpublic static void main(String[])
. (Let op, de naam van het argument van de methode is geen deel van de signatuur).Roep die methode aan en geef het de command line argumenten ("fred", "joe", "bert") als een
String[]
. Redenen waarom Java de class niet kan vindenWanneer je de boodschap "Could not find or load main class ..." krijgt, betekent dit dat de eerste stap is mislukt. Het
java
commando was niet in staat om de class te vinden. En inderdaad, de "..." in de boodschap zal de volledig gekwalificeerde class naam zijn waarjava
naar zoekt. Dus waarom zou het niet in staat zijn om de klasse te vinden?Reden #1 - je hebt een fout gemaakt met het classname argument
De eerste waarschijnlijke oorzaak is dat je de verkeerde classnaam hebt opgegeven. (Of ... de juiste klassenaam, maar in de verkeerde vorm.) In het bovenstaande voorbeeld zijn er een aantal verkeerde manieren om de klassenaam te specificeren:
Voorbeeld #1 - een eenvoudige klassenaam:
Als de klasse wordt gedeclareerd in een pakket zoals
com.acme.example
, dan moet je de volledige klasse-naam gebruiken inclusief de pakketnaam in hetjava
commando; bijv. java com.acme.example.ListUserVoorbeeld #2 - een bestandsnaam of padnaam in plaats van een class naam: java ListUser.class java com/acme/voorbeeld/ListUser.class
Voorbeeld #3 - een klasse-naam met een onjuiste schrijfwijze: java com.acme.example.listuser
Voorbeeld #4 - een tikfout java com.acme.example.mistuser
Voorbeeld #5 - een bron bestandsnaam java ListUser.java
Voorbeeld #6 - je bent de klasse naam helemaal vergeten java veel argumenten Reden #2 - het classpath van de toepassing's is onjuist gespecificeerd
De tweede waarschijnlijke oorzaak is dat de class naam correct is, maar dat het
java
commando de class niet kan vinden. Om dit te begrijpen, moet je het concept van het "classpath" begrijpen. Dit wordt goed uitgelegd in de Oracle documentatie:De
java
commando documentatieHet instellen van het classpath.
De Java Tutorial - PATH en CLASSPATH Dus ... als je de classnaam correct hebt opgegeven, is het volgende wat je moet controleren of je het classpath correct hebt opgegeven:
java
commando uitvoert. Controleer of de directorynamen en JAR-bestandsnamen correct zijn.java
commando uitvoert.Merk op dat de syntax van het classpath verschillend is voor Windows versus Linux en Mac OS. (Het klassepadscheidingsteken is
;
onder Windows en:
onder de andere. Als je het verkeerde scheidingsteken voor je platform gebruikt, krijg je geen expliciete foutmelding. In plaats daarvan krijg je een niet-bestaand bestand of map op het pad dat stilzwijgend wordt genegeerd). Reden #2a - de verkeerde directory staat op het classpathWanneer je een directory op het classpath zet, komt die notioneel overeen met de root van de gekwalificeerde naamruimte. Klassen bevinden zich in de mappenstructuur onder die root, door de volledig gekwalificeerde naam in een padnaam om te zetten. Dus bijvoorbeeld, als "/usr/local/acme/classes" op het class pad staat, dan zal de JVM, wanneer hij zoekt naar een class genaamd
com.acme.example.Foon
, zoeken naar een ".class" bestand met deze padnaam:Als je "/usr/local/acme/classes/com/acme/example" op het classpath had gezet, dan zou de JVM'niet in staat zijn om de class te vinden. Reden #2b - het pad van de subdirectory komt niet overeen met de FQN
Als je klassen FQN
com.acme.example.Foon
is, dan zal de JVM zoeken naar "Foon.class" in de directory "com/acme/example":com.acme.example.Foon
class wilt draaien,/usr/local/acme/classes/com/acme/example/Foon.class
,/usr/local/acme/classes/com/acme/example/
, dan:Opmerkingen:
De
-classpath
optie kan in de meeste Java releases worden afgekort tot-cp
. Zie de respectievelijke handleidingen voorjava
,javac
enzovoort.Denk goed na bij het kiezen tussen absolute en relatieve padnamen in classpaths. Bedenk dat een relatieve padnaam kan breken als de huidige directory verandert.
Reden #2c - ontbrekende dependencies in het classpath
Het classpath moet alle andere (niet-systeem) classes bevatten waar je applicatie van afhankelijk is. (De systeemklassen worden automatisch gelokaliseerd, en je hoeft je hier zelden mee bezig te houden). Om de hoofdklasse correct te laden, moet de JVM vinden:
de klasse zelf.
alle klassen en interfaces in de superclass hiërarchie (zie bijvoorbeeld https://stackoverflow.com/questions/42880748)
alle klassen en interfaces waarnaar verwezen wordt door middel van variabelen of variabelen declaraties, of methode aanroep of veld toegang expressies. (Opmerking: de JLS en JVM specificaties staan enige ruimte toe voor een JVM om klassen "lazily" te laden, en dit kan van invloed zijn op wanneer een classloader exception wordt gegooid). Reden #3 - de klasse is gedeclareerd in het verkeerde package
Het gebeurt wel eens dat iemand een broncode bestand in de verkeerde map in hun source code tree zet, of ze laten de
package
declaratie weg. Als je dit in een IDE doet, zal de IDE's compiler je dit onmiddellijk vertellen. Evenzo als je een fatsoenlijke Java build tool gebruikt, zal de tooljavac
uitvoeren op een manier die het probleem zal detecteren. Echter, als je je Java code met de hand bouwt, kun je het op zo'n manier doen dat de compiler het probleem niet'opmerkt, en het resulterende ".class" bestand staat niet op de plaats waar je het verwacht te hebben. Kunt u het probleem nog steeds niet vinden?Er zijn veel dingen om te controleren, en het is makkelijk om iets te missen. Probeer de
-Xdiag
optie toe te voegen aan dejava
commandolijn (als eerste najava
). Deze optie zal verschillende dingen over het laden van de class weergeven, en dit kan je aanwijzingen geven over wat het echte probleem is. Denk ook aan mogelijke problemen veroorzaakt door het kopiëren en plakken van onzichtbare of niet-ASCII tekens van websites, documenten, enzovoort. En denk aan "homoglyphs", waarbij twee letters of symbolen er hetzelfde uitzien ... maar dat niet zijn.De
java -jar
syntaxisDe alternatieve syntaxis die gebruikt wordt voor "executable" JAR bestanden is als volgt:
b.v.
In dit geval worden de naam van de entry-point class (d.w.z.
com.acme.example.ListUser
) en het classpath gespecificeerd in de MANIFEST van het JAR bestand.IDE's
Een typische Java IDE heeft ondersteuning voor het draaien van Java applicaties in de IDE JVM zelf of in een child JVM. Deze zijn algemeen immuun voor deze specifieke uitzondering, omdat de IDE zijn eigen mechanismen gebruikt om het runtime classpath samen te stellen, de hoofdklasse te identificeren en de
java
commandoregel aan te maken. Het is echter nog steeds mogelijk dat deze uitzondering zich voordoet, als je dingen achter de rug van de IDE doet. Bijvoorbeeld, als je eerder een Application Launcher hebt ingesteld voor je Java app in Eclipse, en je hebt toen het JAR bestand met de "main" class verplaatst naar een andere plaats in het bestandssysteem zonder Eclipse dit te vertellen, dan zou Eclipse onbewust de JVM starten met een incorrect classpath. In het kort, als je dit probleem krijgt in een IDE, controleer dan op zaken als stale IDE state, broken project references of broken launcher configuraties. Het is ook mogelijk dat een IDE gewoon in de war raakt. IDE's zijn enorm ingewikkelde stukken software die bestaan uit veel op elkaar inwerkende onderdelen. Veel van deze onderdelen gebruiken verschillende caching-strategieën om de IDE als geheel responsief te maken. Deze kunnen soms fout gaan, en een mogelijk symptoom is problemen bij het starten van toepassingen. Als u vermoedt dat dit zou kunnen gebeuren, is het de moeite waard om uw IDE opnieuw op te starten en het project opnieuw te bouwen.Andere referenties
Soms heeft wat het probleem veroorzaakt niets te maken met de hoofdklasse, en ik moest dit op de harde manier ontdekken. Het was een gerefereerde bibliotheek die ik verplaatste, en het gaf me de:
Kon de hoofdklasse xxx Linux niet vinden of laden
Ik verwijderde gewoon die referentie, voegde hem weer toe, en het werkte weer prima.
Stel eerst het pad in met dit commando;
Dan moet je het programma laden. Type "cd (mapnaam)" in de opgeslagen drive en compileer het. Bijvoorbeeld, als mijn programma is opgeslagen op de D-schijf, typ "D:" druk op enter en typ " cd (mapnaam)".