Et almindeligt problem, som nye Java-udviklere oplever, er, at deres programmer ikke kan køres med en fejlmeddelelse: Kunne ikke finde eller indlæse hovedklassen ...
Hvad betyder dette, hvad skyldes det, og hvordan skal du løse det?
java <class-name>
Først og fremmest skal du forstå den korrekte måde at starte et program på ved hjælp af kommandoen java
(eller javaw
).
Den normale syntaks1 er denne:
java [ <option> ... ] <class-name> [<argument> ...]
hvor <option>
er en kommandolinjeindstilling (begyndende med et "-" tegn), <class-name>
er et fuldt kvalificeret Java-klasses navn, og <argument>
er et vilkårligt kommandolinjeargument, som sendes til dit program.
1 - Der findes en anden syntaks for "eksekverbare" JAR-filer, som jeg vil beskrive nederst.
Det fuldt kvalificerede navn (FQN) for klassen skrives konventionelt som i Java-kildekode; f.eks.
packagename.packagename2.packagename3.ClassName
Nogle versioner af kommandoen java
tillader dog, at du bruger skråstreger i stedet for punktum; f.eks.
packagename/packagename2/packagename3/ClassName
som (til forvirring) ligner et filpatnavn, men som ikke er et. Bemærk, at udtrykket fuldt kvalificeret navn er standard Java-terminologi ... ikke noget jeg lige har fundet på for at forvirre dig :-)
Her er et eksempel på, hvordan en java
-kommando skal se ud:
java -Xmx100m com.acme.example.ListUsers fred joe bert
Ovenstående vil få java
-kommandoen til at gøre følgende:
com.acme.example.ListUsers
.main
-metode med signatur, return type og modifikatorer givet ved public static void main(String[])
. (Bemærk, metodeargument's navn er IKKE en del af signaturen).String[]
.
Årsager til, at Java ikke kan finde klassenjava
var ikke i stand til at finde klassen. Og faktisk vil " ..." i meddelelsen være det fuldstændigt kvalificerede klasse-navn, som java
leder efter.
Så hvorfor kan den ikke finde klassen?Den første sandsynlige årsag er, at du måske har angivet det forkerte class name. (Eller ... det rigtige class name, men i den forkerte form.) I betragtning af eksemplet ovenfor er der her en række forkerte måder at angive class name på:
Eksempel #1 - et simpelt klassens navn:
java ListUser
Når klassen er deklareret i en pakke som f.eks. com.acme.example
, så skal du bruge det fulde klasse-navn inklusive pakkenavnet i java
-kommandoen; f.eks.
java com.acme.example.ListUser
Eksempel #2 - et filnavn eller et stinavn i stedet for et klassens navn: java ListUser.class java com/acme/acme/eksempel/ListUser.class
Eksempel 3 - et klassens navn med forkert kasus: java com.acme.example.listuser
Eksempel 4 - en slåfejl java com.acme.example.mistuser
Eksempel nr. 5 - et kildefilnavn java ListUser.java
Den anden sandsynlige årsag er, at klassens navn er korrekt, men at kommandoen java
ikke kan finde klassen. For at forstå dette er du nødt til at forstå begrebet "classpath". Dette er forklaret godt i Oracle-dokumentationen:
Java Tutorial - PATH og CLASSPATH Så ... hvis du har angivet klassens navn korrekt, er det næste du skal kontrollere, at du har angivet classpath korrekt:
java
. Kontroller, at mappenavnene og JAR-filnavnene er korrekte.java
.;
på Windows og :
på de andre. Hvis du bruger den forkerte separator for din platform, får du ikke en eksplicit fejlmeddelelse. I stedet får du en ikke-eksisterende fil eller mappe på stien, som vil blive ignoreret i stilhed).
Årsag #2a - den forkerte mappe er på classpathNår du placerer en mappe på classpath, svarer den teoretisk set til roden af det kvalificerede navnerum. Klasser er placeret i mappestrukturen under denne rod ved at mappe det fuldt kvalificerede navn til et vejnavn. Så hvis f.eks. "/usr/local/acme/classes" er på klassestien, så vil JVM'en, når den leder efter en klasse kaldet com.acme.example.Foon
, lede efter en ".class" fil med dette vejnavn:
/usr/local/acme/classes/com/acme/example/Foon.class
Hvis FQN for din klasse er com.acme.example.Foon
, så vil JVM'en søge efter "Foon.class" i mappen "com/acme/example":
com.acme.example.Foon
,/usr/local/acme/classes/com/acme/example/Foon.class
,/usr/local/acme/classes/com/acme/example/
,
så:# 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
Noter:
Indstillingen -classpath
kan forkortes til -cp
i de fleste Java-udgaver. Se de respektive manualposter for java
, javac
osv.
Classpath skal indeholde alle de andre (ikke-systemiske) klasser, som din applikation er afhængig af. (Systemklasserne findes automatisk, og du behøver sjældent at bekymre dig om dette). For at hovedklassen kan indlæses korrekt, skal JVM'en finde følgende:
selve klassen.
alle klasser og grænseflader i overklassens hierarki (se f.eks. https://stackoverflow.com/questions/42880748)
package
-deklarationen. Hvis du gør dette i en IDE, vil IDE's compiler fortælle dig om dette med det samme. Hvis du bruger et ordentligt Java build-værktøj, vil værktøjet ligeledes køre javac
på en sådan måde, at det opdager problemet. Men hvis du bygger din Java-kode i hånden, kan du gøre det på en sådan måde, at compileren ikke bemærker problemet, og den resulterende ".class" fil ikke ligger det sted, du forventer, at den skal være.
Kan du stadig ikke finde problemet?-Xdiag
til java
-kommandolinjen (som det første efter java
). Den vil outputte forskellige ting om class loading, og det kan give dig fingerpeg om, hvad det egentlige problem er.
Overvej også mulige problemer, der skyldes kopiering og indsættelse af usynlige eller ikke-ASCII-tegn fra websteder, dokumenter osv. Og tænk på "homoglyffer", hvor to bogstaver eller symboler ser ens ud ... men ikke er det.java -jar <jar-fil>
Den alternative syntaks, der anvendes til "eksekverbare" JAR-filer, er som følger:
java [ <option> ... ] -jar <jar-file-name> [<argument> ...]
f.eks.
java -Xmx100m -jar /usr/local/acme-example/listuser.jar fred
com.acme.example.ListUser
) og classpath angivet i JAR-filens MANIFEST.java
-kommandolinjen.
Det er dog stadig muligt, at denne undtagelse kan forekomme, hvis du gør ting bag IDE'ens ryg. Hvis du f.eks. tidligere har oprettet en Application Launcher for din Java-app i Eclipse, og du derefter har flyttet JAR-filen med klassen "main" til et andet sted i filsystemet uden at fortælle Eclipse det, vil Eclipse uden at vide det starte JVM'en med en forkert classpath.
Kort sagt, hvis du får dette problem i et IDE, skal du tjekke for ting som forældet IDE-status, ødelagte projektreferencer eller ødelagte launcher-konfigurationer.
Det er også muligt, at en IDE simpelthen bliver forvirret. IDE'er er enormt komplicerede stykker software, der består af mange interagerende dele. Mange af disse dele anvender forskellige caching-strategier for at gøre IDE'et som helhed responsivt. Disse kan nogle gange gå galt, og et muligt symptom er problemer ved start af programmer. Hvis du har mistanke om, at dette kan ske, er det værd at prøve ting lie genstarte dit IDE og genopbygge projektet.Nogle gange har det, der kan være årsag til problemet, intet at gøre med hovedklassen, og det måtte jeg finde ud af på den hårde måde. Det var et refereret bibliotek, som jeg flyttede, og det gav mig den:
Could not find or load main class xxx Linux
Jeg slettede bare den reference, tilføjede den igen, og så virkede det fint igen.
Indstil først stien ved hjælp af denne kommando;
set path="paste the set path address"
Derefter skal du indlæse programmet. Skriv "cd (mappenavn)" i det gemte drev og kompilér det. Hvis mit program f.eks. er gemt på D-drevet, skal du skrive "D:" tryk på enter og skriv " cd (mappenavn)".