Ένα συνηθισμένο πρόβλημα που αντιμετωπίζουν οι νέοι προγραμματιστές Java είναι ότι τα προγράμματά τους αποτυγχάνουν να τρέξουν με το μήνυμα σφάλματος: Δεν μπόρεσε να βρει ή να φορτώσει την κύρια κλάση ...
Τι σημαίνει αυτό, τι το προκαλεί και πώς πρέπει να το διορθώσετε;
java <class-name>
Πρώτα απ' όλα, πρέπει να κατανοήσετε τον σωστό τρόπο εκκίνησης ενός προγράμματος με την εντολή java
(ή javaw
).
Η κανονική σύνταξη1 είναι η εξής:
java [ <option> ... ] <class-name> [<argument> ...]
όπου <option>
είναι μια επιλογή γραμμής εντολών (που αρχίζει με τον χαρακτήρα "-"),
είναι ένα πλήρως προσδιορισμένο όνομα κλάσης Java, και
1 - Υπάρχει μια δεύτερη σύνταξη για τα "εκτελέσιμα" αρχεία JAR την οποία θα περιγράψω στο τέλος.</sup>,
Το πλήρως προσδιορισμένο όνομα (FQN) για την κλάση γράφεται συμβατικά όπως θα γράφατε στον πηγαίο κώδικα της Java- π.χ.
packagename.packagename2.packagename3.ClassName
Ωστόσο, ορισμένες εκδόσεις της εντολής java
σας επιτρέπουν να χρησιμοποιείτε κάθετους αντί για τελείες- π.χ.
packagename/packagename2/packagename3/ClassName
το οποίο (με σύγχυση) μοιάζει με όνομα διαδρομής αρχείου, αλλά δεν είναι. Σημειώστε ότι ο όρος πλήρως προσδιορισμένο όνομα είναι τυπική ορολογία της Java ... όχι κάτι που επινόησα για να σας μπερδέψω :-)
Ακολουθεί ένα παράδειγμα του πώς πρέπει να μοιάζει μια εντολή java
:
java -Xmx100m com.acme.example.ListUsers fred joe bert
Το παραπάνω θα προκαλέσει την εντολή java
να κάνει τα εξής:
com.acme.example.ListUsers
.main
με υπογραφή, τύπο επιστροφής και τροποποιητές που δίνονται από την public static void main(String[])
. (Σημειώστε, το όνομα του ορίσματος της μεθόδου'δεν αποτελεί ΔΕΝ μέρος της υπογραφής).String[]
.
Λόγοι για τους οποίους η Java δεν μπορεί να βρει την κλάσηjava
δεν μπόρεσε να βρει την κλάση. Και πράγματι, το "..." στο μήνυμα θα είναι το πλήρως προσδιορισμένο όνομα κλάσης που αναζητά η java
.
Οπότε γιατί μπορεί να μην μπορεί να βρει την κλάση;Η πρώτη πιθανή αιτία είναι ότι μπορεί να δώσατε λάθος όνομα κλάσης. (Ή ... το σωστό όνομα κλάσης, αλλά σε λάθος μορφή.) Λαμβάνοντας υπόψη το παραπάνω παράδειγμα, υπάρχουν διάφοροι λανθασμένοι τρόποι για να καθορίσετε το όνομα της κλάσης:
Παράδειγμα #1 - ένα απλό όνομα κλάσης:
java ListUser
Όταν η κλάση δηλώνεται σε ένα πακέτο όπως το com.acme.example
, τότε πρέπει να χρησιμοποιήσετε το πλήρες όνομα της κλάσης συμπεριλαμβανομένου του ονόματος του πακέτου στην εντολή java
- π.χ.
java com.acme.example.ListUser
Παράδειγμα #2 - ένα όνομα αρχείου ή ένα όνομα διαδρομής αντί για ένα όνομα κλάσης: java ListUser.class java com/acme/example/ListUser.class
Παράδειγμα #3 - ένα όνομα κλάσης με λανθασμένη περιβάλλουσα: java com.acme.example.listuser
Παράδειγμα #4 - τυπογραφικό λάθος java com.acme.example.mistuser
Παράδειγμα #5 - ένα όνομα αρχείου πηγής java ListUser.java
Η δεύτερη πιθανή αιτία είναι ότι το όνομα της κλάσης είναι σωστό, αλλά η εντολή java
δεν μπορεί να βρει την κλάση. Για να το καταλάβετε αυτό, πρέπει να κατανοήσετε την έννοια του "classpath". Αυτό εξηγείται καλά από την τεκμηρίωση της Oracle:
The Java Tutorial - PATH και CLASSPATH Έτσι ... αν έχετε καθορίσει σωστά το όνομα της κλάσης, το επόμενο πράγμα που πρέπει να ελέγξετε είναι ότι έχετε καθορίσει σωστά το classpath:
java
. Ελέγξτε ότι τα ονόματα των καταλόγων και των αρχείων JAR είναι σωστά.java
.;
στα Windows και :
στα υπόλοιπα. Αν χρησιμοποιήσετε λάθος διαχωριστικό για την πλατφόρμα σας, δεν θα λάβετε ρητό μήνυμα σφάλματος. Αντ' αυτού, θα λάβετε ένα ανύπαρκτο αρχείο ή κατάλογο στη διαδρομή που θα αγνοηθεί σιωπηρά).
Λόγος #2α - ο λάθος κατάλογος βρίσκεται στο classpathΌταν τοποθετείτε έναν κατάλογο στο μονοπάτι κλάσεων, αυτός αντιστοιχεί νοητά στη ρίζα του χώρου ονομάτων με προσόντα. Οι κλάσεις εντοπίζονται στη δομή καταλόγων κάτω από αυτή τη ρίζα, με την αντιστοίχιση του πλήρως προσδιορισμένου ονόματος σε ένα όνομα διαδρομής. Έτσι, για παράδειγμα, εάν το "/usr/local/acme/classes" βρίσκεται στο μονοπάτι κλάσεων, τότε όταν η JVM αναζητά μια κλάση με όνομα com.acme.example.Foon
, θα αναζητήσει ένα αρχείο ".class" με αυτό το όνομα διαδρομής:
/usr/local/acme/classes/com/acme/example/Foon.class
Εάν το FQN των κλάσεών σας είναι com.acme.example.Foon
, τότε η JVM θα αναζητήσει την "Foon.class" στον κατάλογο "com/acme/example":
com.acme.example.Foon
,/usr/local/acme/classes/com/acme/example/Foon.class
,/usr/local/acme/classes/com/acme/example/
,
τότε:# 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
Σημειώσεις:
Η επιλογή -classpath
μπορεί να συντομευτεί σε -cp
στις περισσότερες εκδόσεις της Java. Ελέγξτε τις αντίστοιχες καταχωρήσεις του εγχειριδίου για java
, javac
και ούτω καθεξής.
Το classpath πρέπει να περιλαμβάνει όλες τις άλλες (μη συστημικές) κλάσεις από τις οποίες εξαρτάται η εφαρμογή σας. (Οι κλάσεις συστήματος εντοπίζονται αυτόματα και σπάνια χρειάζεται να ασχοληθείτε με αυτό). Για να φορτωθεί σωστά η κύρια κλάση, η JVM πρέπει να βρει:
την ίδια την κλάση.
όλες τις κλάσεις και τις διεπαφές στην ιεραρχία των υπερκλάσεων (π.χ. βλέπε https://stackoverflow.com/questions/42880748)
package
. Αν το κάνετε αυτό σε ένα IDE, ο μεταγλωττιστής του IDE'θα σας το πει αμέσως. Ομοίως, αν χρησιμοποιείτε ένα αξιοπρεπές εργαλείο κατασκευής Java, το εργαλείο θα εκτελέσει το javac
με τρόπο που θα εντοπίσει το πρόβλημα. Ωστόσο, αν χτίζετε τον κώδικα Java σας με το χέρι, μπορείτε να το κάνετε με τέτοιο τρόπο ώστε ο μεταγλωττιστής να μην αντιληφθεί το πρόβλημα και το αρχείο ".class" που προκύπτει να μην είναι στη θέση που περιμένετε να είναι.
Ακόμα δεν μπορείτε να βρείτε το πρόβλημα;-Xdiag
στη γραμμή εντολών java
(ως το πρώτο πράγμα μετά το java
). Θα βγάλει διάφορα πράγματα σχετικά με τη φόρτωση των κλάσεων, και αυτό μπορεί να σας προσφέρει ενδείξεις για το ποιο είναι το πραγματικό πρόβλημα.
Επίσης, εξετάστε πιθανά προβλήματα που προκαλούνται από την αντιγραφή και επικόλληση αόρατων ή μη ASCII χαρακτήρων από ιστοσελίδες, έγγραφα κ.λπ. Και λάβετε υπόψη σας τα "ομογλυφικά", όπου δύο γράμματα ή σύμβολα φαίνονται ίδια ... αλλά δεν είναι.java -jar <jar file>
Η εναλλακτική σύνταξη που χρησιμοποιείται για τα "εκτελέσιμα" αρχεία JAR είναι η ακόλουθη:
java [ <option> ... ] -jar <jar-file-name> [<argument> ...]
π.χ.
java -Xmx100m -jar /usr/local/acme-example/listuser.jar fred
com.acme.example.ListUser
) και το classpath καθορίζονται στο MANIFEST του αρχείου JAR.java
.
Ωστόσο, είναι ακόμα πιθανό να εμφανιστεί αυτή η εξαίρεση, αν κάνετε πράγματα πίσω από την πλάτη του IDE. Για παράδειγμα, αν έχετε προηγουμένως ρυθμίσει έναν εκτοξευτή εφαρμογών για την εφαρμογή Java στο Eclipse και στη συνέχεια μετακινήσετε το αρχείο JAR που περιέχει την κλάση "main" σε ένα διαφορετικό μέρος στο σύστημα αρχείων χωρίς να το πείτε στο Eclipse, το Eclipse θα εκκινήσει άθελά του την JVM με λανθασμένο classpath.
Εν ολίγοις, αν αντιμετωπίσετε αυτό το πρόβλημα σε ένα IDE, ελέγξτε για πράγματα όπως η κατάσταση του IDE που έχει μείνει στάσιμη, σπασμένες αναφορές έργων ή σπασμένες διαμορφώσεις εκτοξευτή.
Είναι επίσης πιθανό για ένα IDE να μπερδευτεί απλά. Τα IDE's είναι εξαιρετικά περίπλοκα κομμάτια λογισμικού που περιλαμβάνουν πολλά αλληλεπιδρώντα μέρη. Πολλά από αυτά τα μέρη υιοθετούν διάφορες στρατηγικές προσωρινής αποθήκευσης, προκειμένου το IDE να ανταποκρίνεται στο σύνολό του. Αυτές μπορεί μερικές φορές να πάνε στραβά, και ένα πιθανό σύμπτωμα είναι τα προβλήματα κατά την εκκίνηση των εφαρμογών. Αν υποψιάζεστε ότι αυτό μπορεί να συμβαίνει, αξίζει να δοκιμάσετε πράγματα όπως η επανεκκίνηση του IDE σας και η επαναδημιουργία του έργου.Μερικές φορές αυτό που μπορεί να προκαλεί το πρόβλημα δεν έχει καμία σχέση με την κύρια κλάση, και έπρεπε να το ανακαλύψω αυτό με τον δύσκολο τρόπο. Ήταν μια βιβλιοθήκη στην οποία αναφερόμουν και την οποία μετακίνησα, και μου έδωσε το:
Δεν μπόρεσε να βρει ή να φορτώσει την κύρια κλάση xxx Linux
Απλώς διέγραψα αυτή την αναφορά, την πρόσθεσα ξανά και δούλεψε και πάλι μια χαρά.
Αρχικά ορίστε τη διαδρομή χρησιμοποιώντας αυτή την εντολή,
set path="paste the set path address"
Στη συνέχεια πρέπει να φορτώσετε το πρόγραμμα. Πληκτρολογήστε "cd (όνομα φακέλου)" στην αποθηκευμένη μονάδα δίσκου και μεταγλωττίσετε το. Για παράδειγμα, αν το πρόγραμμά μου είναι αποθηκευμένο στο δίσκο D, πληκτρολογήστε "D:" πατήστε enter και πληκτρολογήστε " cd (όνομα φακέλου)".