Cosa significa "Impossibile trovare o caricare la classe principale"?
Un problema comune che i nuovi sviluppatori Java sperimentano è che i loro programmi non riescono a funzionare con il messaggio di errore: "Impossibile trovare o caricare la classe principale...`
Cosa significa questo, cosa lo causa e come si dovrebbe risolvere?
1270
3
La sintassi del comando
java
Prima di tutto, devi capire il modo corretto di lanciare un programma usando il comando
java
(ojavaw
). La sintassi normale1 è questa:dove
è un'opzione della linea di comando (che inizia con un carattere "-"),
è un nome di classe Java pienamente qualificato, e `` è un argomento arbitrario della linea di comando che viene passato alla tua applicazione.1 - C'è una seconda sintassi per i file JAR "eseguibili" che descriverò in fondo; Il nome pienamente qualificato (FQN) per la classe è convenzionalmente scritto come si farebbe nel codice sorgente Java; ad esempio
Tuttavia alcune versioni del comando
java
permettono di usare slash al posto dei punti; ad es.che (confusamente) sembra un percorso di file, ma non lo è. Notate che il termine nome completamente qualificato è terminologia Java standard ... non qualcosa che ho inventato per confondervi :-) Ecco un esempio di come dovrebbe essere un comando
java
:Quanto sopra farà sì che il comando
java
faccia quanto segue:com.acme.example.ListUsers
.main
con signature, return type e modificatori dati dapublic static void main(String[])
. (Nota, il nome dell'argomento del metodo è NON parte della firma).Chiama quel metodo passandogli gli argomenti della linea di comando ("fred", "joe", "bert") come
String[]
. Motivi per cui Java non riesce a trovare la classeQuando ottieni il messaggio "Could not find or load main class ...", significa che il primo passo è fallito. Il comando
java
non è riuscito a trovare la classe. E infatti, il "..." nel messaggio sarà il nome della classe qualificata chejava
sta cercando. Quindi perché potrebbe non essere in grado di trovare la classe?Motivo #1 - hai fatto un errore con l'argomento classname
La prima probabile causa è che tu possa aver fornito il nome della classe sbagliato. (O ... il nome giusto della classe, ma nella forma sbagliata.) Considerando l'esempio precedente, ecco una varietà di modi sbagliati per specificare il nome della classe:
Esempio #1 - un semplice nome di classe:
Quando la classe è dichiarata in un pacchetto come
com.acme.example
, allora devi usare il nome completo della classe incluso il nome del pacchetto nel comandojava
; ad esempio java com.acme.example.ListUserEsempio #2 - un nome di file o un percorso piuttosto che un nome di classe: java ListUser.class java com/acme/example/ListUser.class
Esempio #3 - un nome di classe con il casing errato: java com.acme.example.listuser
Esempio #4 - un errore di battitura java com.acme.example.mistuser
Esempio #5 - un nome di file sorgente java ListUser.java
Esempio #6 - hai dimenticato completamente il nome della classe java molti argomenti Motivo #2 - il classpath dell'applicazione non è specificato correttamente
La seconda probabile causa è che il nome della classe sia corretto, ma che il comando
java
non riesca a trovare la classe. Per capire questo, è necessario comprendere il concetto di "classpath". Questo è spiegato bene dalla documentazione Oracle:La documentazione del comando
java
Impostazione del classpath.
Il tutorial Java - PATH e CLASSPATH Quindi ... se avete specificato correttamente il nome della classe, la prossima cosa da controllare è che abbiate specificato correttamente il classpath:
java
. Controllate che i nomi delle directory e dei file JAR siano corretti.java
.Nota che la sintassi del classpath è diversa per Windows rispetto a Linux e Mac OS. (Il separatore di classpath è
;
su Windows e:
sugli altri. Se usi il separatore sbagliato per la tua piattaforma, non riceverai un messaggio di errore esplicito. Invece, otterrete un file o una directory inesistente sul percorso che verrà silenziosamente ignorato). Motivo #2a - la directory sbagliata è nel classpathQuando mettete una directory nel classpath, essa corrisponde teoricamente alla radice dello spazio dei nomi qualificati. Le classi si trovano nella struttura di directory sotto quella radice, mappando il nome pienamente qualificato ad un percorso. Così, per esempio, se "/usr/local/acme/classes" è nel percorso della classe, allora quando la JVM cerca una classe chiamata
com.acme.example.Foon
, cercherà un file ".class" con questo pathname:Se tu avessi messo "/usr/local/acme/classes/com/acme/example" nel classpath, allora la JVM non sarebbe in grado di trovare la classe. Motivo #2b - il percorso della sottodirectory non corrisponde al FQN
Se la tua classe FQN è
com.acme.example.Foon
, allora la JVM cercherà "Foon.class" nella directory "com/acme/example":com.acme.example.Foon
,/usr/local/acme/classes/com/acme/example/Foon.class
,/usr/local/acme/classes/com/acme/example/
, allora:Note:
L'opzione
-classpath
può essere abbreviata in-cp
nella maggior parte delle versioni di Java. Controlla le rispettive voci di manuale perjava
,javac
e così via.Pensaci bene quando scegli tra nomi di percorso assoluti e relativi nei classpath. Ricordate che un pathname relativo può "rompere" se la directory corrente cambia.
Motivo #2c - dipendenze mancanti dal classpath
Il classpath deve includere tutte le altre classi (non di sistema) da cui dipende la tua applicazione. (Le classi di sistema sono localizzate automaticamente, e raramente hai bisogno di preoccupartene). Per caricare correttamente la classe principale, la JVM deve trovare:
la classe stessa.
tutte le classi e le interfacce nella gerarchia delle superclassi (per esempio, vedi https://stackoverflow.com/questions/42880748)
tutte le classi e le interfacce a cui si fa riferimento per mezzo di dichiarazioni di variabili o variabili, o espressioni di chiamata di metodo o di accesso al campo. (Nota: le specifiche JLS e JVM permettono ad una JVM di caricare classi "pigramente", e questo può influenzare quando viene lanciata un'eccezione classloader). Motivo #3 - la classe è stata dichiarata nel pacchetto sbagliato
Succede occasionalmente che qualcuno metta un file di codice sorgente nella nella cartella sbagliata nel loro albero del codice sorgente, o tralascia la dichiarazione
package
. Se lo fate in un IDE, il compilatore dell'IDE ve lo dirà immediatamente. Allo stesso modo, se si utilizza uno strumento di compilazione Java decente, lo strumento eseguiràjavac
in modo da rilevare il problema. Tuttavia, se costruisci il tuo codice Java a mano, puoi farlo in modo tale che il compilatore non noti il problema, e il file ".class" risultante non è nel posto che ti aspetti che sia. Non riesci ancora a trovare il problema?Ci sono molte cose da controllare, ed è facile perdere qualcosa. Prova ad aggiungere l'opzione
-Xdiag
alla linea di comandojava
(come prima cosa dopojava
). Mostrerà varie cose sul caricamento delle classi, e questo potrebbe offrirti indizi su quale sia il vero problema. Inoltre, considera possibili problemi causati dal copiare e incollare caratteri invisibili o non-ASCII da siti web, documenti e così via. E considerate gli "omografi", dove due lettere o simboli sembrano uguali... ma non lo sono.La sintassi
java -jar
La sintassi alternativa usata per i file JAR "eseguibili" è la seguente:
ad es.
In questo caso il nome della classe entry-point (cioè
com.acme.example.ListUser
) e il classpath sono specificati nel MANIFEST del file JAR.IDE
Un tipico IDE Java ha il supporto per eseguire applicazioni Java nella stessa JVM dell'IDE o in una JVM figlia. Questi sono generalmente immuni da questa particolare eccezione, perché l'IDE usa i propri meccanismi per costruire il classpath di runtime, identificare la classe principale e creare la linea di comando
java
. Tuttavia è ancora possibile che questa eccezione si verifichi, se si fanno cose alle spalle dell'IDE. Per esempio, se avete precedentemente impostato un Application Launcher per la vostra applicazione Java in Eclipse, e poi avete spostato il file JAR che contiene la classe "main" in un posto diverso nel file system senza dirlo a Eclipse, Eclipse potrebbe involontariamente lanciare la JVM con un classpath errato. In breve, se avete questo problema in un IDE, controllate cose come lo stato stantio dell'IDE, riferimenti al progetto non funzionanti o configurazioni del lanciatore non corrette. È anche possibile che un IDE sia semplicemente confuso. Gli IDE sono pezzi di software enormemente complicati che comprendono molte parti che interagiscono. Molte di queste parti adottano varie strategie di caching per rendere l'IDE nel suo complesso reattivo. Queste possono a volte andare male, e un possibile sintomo sono i problemi quando si lanciano le applicazioni. Se sospettate che questo possa accadere, vale la pena provare cose come riavviare l'IDE e ricostruire il progetto.Altri riferimenti
A volte ciò che potrebbe causare il problema non ha nulla a che fare con la classe principale, e ho dovuto scoprirlo nel modo più difficile. Era una libreria di riferimento che ho spostato, e mi ha dato il:
Impossibile trovare o caricare la classe principale xxx Linux
Ho semplicemente cancellato quel riferimento, l'ho aggiunto di nuovo e ha funzionato di nuovo bene.
Prima imposta il percorso usando questo comando;
Poi devi caricare il programma. Digita "cd (nome della cartella)" nell'unità memorizzata e compilalo. Per esempio, se il mio programma è memorizzato nell'unità D, digitate "D:" premete invio e digitate " cd (nome cartella)".