Hvad betyder "Kunne ikke finde eller indlæse hovedklassen"?

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?

Løsning

Kommandosyntaksen java

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 [  ... ]  [ ...]

hvor er en kommandolinjeindstilling (begyndende med et "-" tegn), er et fuldt kvalificeret Java-klasses navn, og `` 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:

    1. Søg efter den kompilerede version af klassen com.acme.example.ListUsers.
  1. Indlæs klassen.
  2. Kontroller, at klassen har en 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).
  3. Kald denne metode og giv den kommandolinjeargumenterne ("fred", "joe", "bert") som en String[]. Årsager til, at Java ikke kan finde klassen

    Når du får meddelelsen "Could not find or load main class ...", betyder det, at det første trin er mislykkedes. Kommandoen java 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?
    Årsag #1 - du har lavet en fejl med classname-argumentet

    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

  • Eksempel #6 - du har helt glemt klassens navn java masser af argumenter Årsag #2 - applikation's classpath er forkert angivet

    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:

  • The java command documentation

  • Indstilling af classpath.

  • 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:

  1. Læs de tre dokumenter, der er linket til ovenfor. (Ja ... LÆS dem. Det er vigtigt, at en Java-programmør forstår i det mindste det grundlæggende i, hvordan Java classpath-mekanismerne fungerer).
  2. Se på kommandolinjen og/eller CLASSPATH-miljøvariablen, der er gældende, når du kører kommandoen java. Kontroller, at mappenavnene og JAR-filnavnene er korrekte.
  3. Hvis der er relative stinavne i classpath, skal du kontrollere, at de opløses korrekt ... fra den aktuelle mappe, der er gældende, når du kører kommandoen java.
  4. Kontroller, at klassen (nævnt i fejlmeddelelsen) kan findes på den effektive classpath.
  5. Bemærk, at classpath-syntaksen er forskellig for Windows i forhold til Linux og Mac OS. (Classpath-adskilleren er ; 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å classpath

    Nå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 du havde sat "/usr/local/acme/classes/com/acme/example" på classpath'en, ville JVM'en ikke kunne finde klassen. Årsag #2b - undermappestien passer ikke til FQN'en

Hvis FQN for din klasse er com.acme.example.Foon, så vil JVM'en søge efter "Foon.class" i mappen "com/acme/example":

  • Hvis din mappestruktur ikke passer til pakke navngivningen i henhold til ovenstående mønster, vil JVM'en ikke finde din klasse.
  • Hvis du forsøger at omdøbe en klasse ved at flytte den, vil det også mislykkes ... men undtagelsesstacktrace vil være anderledes. Den vil sandsynligvis sige noget i retning af dette: Caused by: java.lang.NoClassDefFoundError: <path> (wrong name: ) fordi FQN'et i klassefilen ikke passer til det, som klasselæsseren forventer at finde. For at give et konkret eksempel, antager vi, at:
  • du ønsker at køre klassen com.acme.example.Foon,
  • den fulde filsti er /usr/local/acme/classes/com/acme/example/Foon.class,
  • din nuværende arbejdskatalog er /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.

  • Tænk dig godt om, når du vælger mellem absolutte og relative stinavne i classpaths. Husk, at et relativt vejnavn kan "bryde" hvis den aktuelle mappe ændres.
    Årsag #2c - afhængigheder mangler i classpath'en

    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)

  • alle klasser og grænseflader, som der henvises til ved hjælp af variabler eller variabeldeklarationer eller udtryk for metodeopkald eller feltadgang. (Bemærk: JLS og JVM-specifikationerne giver et vist spillerum for, at en JVM kan indlæse klasser "lazily", og dette kan påvirke, hvornår en classloader-undtagelse bliver kastet). Årsag nr. 3 - klassen er blevet erklæret i den forkerte pakke

    Det sker af og til, at nogen lægger en kildekodefil i den forkerte mappe i deres kildekodetræ, eller de udelader 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?

    Der er mange ting at kontrollere, og det er let at overse noget. Prøv at tilføje indstillingen -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.

    Syntaksen java -jar

    Den alternative syntaks, der anvendes til "eksekverbare" JAR-filer, er som følger:

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

f.eks.

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

I dette tilfælde er navnet på entry-point-klassen (dvs. com.acme.example.ListUser) og classpath angivet i JAR-filens MANIFEST.

IDE'er

Et typisk Java-IDE har støtte til at køre Java-programmer i selve IDE JVM'en eller i en underordnet JVM. Disse er generelt immune over for denne særlige undtagelse, fordi IDE'et bruger sine egne mekanismer til at konstruere køretidsklassestien, identificere hovedklassen og oprette 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.

Andre referencer

Kommentarer (11)

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.

Kommentarer (5)

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)".

Kommentarer (3)