Vì sao lỗi “Error: Could not find or load main class” xuất hiện?
Những lý do chính gây ra lỗi “Error: Could not find or load main class“
3 lý do chính khiến chương trình Java của bạn khi chạy và gặp phải lỗi “Error: Could not find or load main class” bao gồm:
- Đặt tên sai và gọi sai tên
- Package bị sai
- Classpath không chính xác/ đường dẫn không chính xác
Ví dụ bằng chương trình cơ bản
Phần lớn những bạn tìm đến bài viết này đều chủ yếu là người mới học Java, vì thế, TinoHost sẽ giải thích thật kỹ giúp bạn và đưa ra ví dụ HelloWorld “thần thánh” dễ hiểu như sau:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
Sau khi biên dịch, chúng ta sẽ được kết quả như sau:
$ javac HelloWorld.java.
Đồng nghĩa với việc chúng ta đã có được một tệp thực thi .class được sinh ra có cùng tên với tên class trong chương trình Java phía trên (public class HelloWorld).
Thay vì làm 2 phần tách biệt bao gồm lỗi và cách sửa lỗi, TinoHost sẽ gom lại thành 1 phần duy nhất: lỗi và cách sửa lỗi ngay trong cùng 1 mục để bạn dễ theo dõi hơn nhé!
Một số từ khóa TinoHost sẽ giữ nguyên trong bài viết:
- Class: lớp
- Package: gói
Cách sửa lỗi “Error: Could not find or load main class“
Lỗi “Error: Could not find or load main class” do đặt tên sai và gọi sai tên
Ví dụ về lỗi đặt sai tên và gọi sai tên
Đây là một lỗi phổ biến rất nhiều người gặp phải vì ngôn ngữ Java phân biệt chữ in hoa và chữ in thường. Ví dụ như sau:
Sau khi bạn đã có được file .class, chúng ta sẽ chạy chương trình bằng lệnh sau:
java <.class tên file>
Áp dụng vào chương trình mẫu ở trên chúng ta sẽ có như sau:
$ java helloworld
Error: Could not find or load main class helloworld
Như bạn thấy, dòng lỗi“Error: Could not find or load main class helloworld” hiện lên vì lý do:
Tệp .class có tên làHelloWorldchứ không phảihelloworld.Đồng nghĩa với việc bạn sẽ phải gõ chính xác “HelloWorld” chương trình của bạn mới có thể chạy được.
Tương tự, thay vì gọi HelloWorld và bạn gọiHeloWorld(thiếu l) hayHelloWord(thiếu l) chương trình cũng sẽ bị lỗi.
Đôi khi bạn sẽ dùng lệnh như sau để chạy:
$ java HelloWorld.class
Error: Could not find or load main class HelloWorld.class
Đồng nghĩa với việc bạn gọi luôn cả phần mở rộng .class của HelloWorld. Tuy nhiên, điều này hoàn toàn không cần thiết và gây ra lỗi “Error: Could not find or load main class.”
Sửa lỗi “Error: Could not find or load main class” do đặt sai tên và gọi sai tên
Suy ra, cách để sửa lỗi này rất đơn giản. Bạn chỉ cầnkiểm tra chính xác tên gọicủa .class bạn đã tạo ở trên. Và trình biên dịch cũng tự động tạo .class có cùng tên với tên class bạn đặt trong chương trình.
Bạn thử lại với đúng cách viết hoa, đúng chính tả và không thêm phần đuôi mở rộng. Chương trình của bạn sẽ không báo lỗi nữa:
$ java HelloWorld
Hello world!
Lỗi “Error: Could not find or load main class” do Package bị sai
Ví dụ về lỗi Package bị sai
Khi sử dụng Java, bạn có thể tạo ra các class tương tự nhau và gói gọn lại trong một package. Và chúng ta sẽ chuyển class HelloWorld vào bên trong gói com.tino như sau:
package com.tino:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
Bây giờ bạn chỉ cần biên dịch sau đó chạy chương trình HelloWorld và chúng ta sẽ được kết quả như sau:
$ java HelloWorld
Error: Could not find or load main class HelloWorld
Sửa lỗi “Error: Could not find or load main class” do Package bị sai
Quá trình nhập của bạn không sai, viết đúng chính tả in hoa nhưng lại không thể chạy được là vì sao?
Lý do:Khi bạn đưa class vào trong package, bạn sẽ cần phải gọi đầy đủ tên của chúng.Vì vậy, trong trường hợp này, bạn sẽ cần gọi đầy đủ package này là:com.tino.HelloWorld.
Với cách tạo này, bạn sẽ tạo ra một thư mục cây như sau: com/tino/HelloWorld.java
Bạn chỉ cần đảm bảo các tệp trong thư mục cây này tồn tại bạn sẽ có thể chạy được chương trình.
$ java com.tino.HelloWorld
Hello world!
Classpath không chính xác/ đường dẫn không chính xác
Classpath là gì?
Classpath là một tham số trong JVM – java Virtual Machine (tạm dịch Máy ảo Java) hoặc trình biên dịch Java nhằm để chỉ vị trí của các class và các package do người dùng thực hiện.
Giải thích đơn giản hơn, bạn có thể sử dụng Classpath để “nói” và hướng dẫn cho JVM, trình biên dịch Java biết tệp .class đang ở đâu trong máy tính của bạn.
Bạn có thể sử dụng lệnh sau:
java -classpath /myprograms/compiled HelloWorld
Và Java sẽ tự động chạy đi tìm theo đường dẫn để đến classHelloWorld.
Sửa lỗi “Error: Could not find or load main class” do Classpath không chính xác
Cách sửa lỗi cũng khá đơn giản như ở phần “Sửa lỗi Error: Could not find or load main class do đặt sai tên và gọi sai tên”. Bạn chỉ cần kiểm tra lại chính xác tên của từng thư mục và tệp trong đường dẫn và tệp class của bạn có tồn tại trong đường dẫn đó hay không.
Giả sử, bạn muốn chạy com.tino.HelloWorld ở một thư mục khác, một tệp khác. Bạn sẽ phải làm như thế nào?
Rất may, nhà phát triển ngôn ngữ Java cũng là lập trình viên và tạo điều kiện thuận lợi hơn trong việc lập trình của các bạn bằng cách: sử dụngdấu chấm ‘.’thay cho tên thư mục là được.
Thay vì sử dụng:java -classpath <tệp mẹ>/<tệp con>/ com.tino.HelloWorld
Bạn chỉ cần thay vào dấu ‘.’:java -classpath ././ com.tino.HelloWorld
Vấn đề của bạn sẽ được giải quyết nhanh hơn, ít lỗi hơn.
Trong trường hợp bạn đang sử dụng các hệ điều hành khác, bạn có thể tham khảo tài liệu gốc của Oracle về PATH và CLASSPATH để hiểu rõ hơn nhé!
Cácjava <class-name>
cú pháp lệnh
Trước hết, bạn cần hiểu đúng cách để khởi chạy một chương trình bằng lệnhjava
(hoặcjavaw
).
Cú pháp bình thường1là đây:
java [ <options> ] <class-name> [<arg> ...]
trong đó<option>
là một tùy chọn dòng lệnh (bắt đầu bằng ký tự “-“),<class-name>
là tên lớp Java đủ điều kiện và<arg>
là một đối số dòng lệnh tùy ý được truyền cho ứng dụng của bạn.
1 – Có một số cú pháp khác được mô tả ở gần cuối câu trả lời này.
Tên đủ điều kiện (FQN) cho lớp được viết theo quy ước như bạn làm trong mã nguồn Java; ví dụ
packagename.packagename2.packagename3.ClassName
Tuy nhiên, một số phiên bản củajava
lệnh cho phép bạn sử dụng dấu gạch chéo thay vì dấu chấm; ví dụ
packagename/packagename2/packagename3/ClassName
mà (khó hiểu) trông giống như một tên đường dẫn tệp, nhưng không phải là một tên. Lưu ý rằng thuật ngữtên đủ điều kiệnlà thuật ngữ Java tiêu chuẩn … không phải là thứ tôi vừa tạo ra để làm bạn bối rối 🙂
Dưới đây là một ví dụ về mộtjava
lệnh sẽ trông như thế nào:
java -Xmx100m com.acme.example.ListUsers fred joe bert
Ở trên sẽ gây rajava
lệnh để làm như sau:
- Tìm kiếm phiên bản biên dịch của
com.acme.example.ListUsers
lớp. - Tải lớp.
- Kiểm tra xem lớp có một
main
phương thức vớichữ ký,kiểu trả vềvà cácsửa đổiđược đưa ra bởipublic static void main(String[])
. (Lưu ý, tên của đối số phương thứcKHÔNG phảilà một phần của chữ ký.) - Gọi phương thức đó truyền cho nó các đối số dòng lệnh (“fred”, “joe”, “bert”) là a
String[]
.
Lý do tại sao Java không thể tìm thấy lớp
Khi bạn nhận được thông báo “Không thể tìm hoặc tải lớp chính …”, điều đó có nghĩa là bước đầu tiên đã thất bại. Cácjava
lệnh đã không thể tìm thấy những lớp. Và quả thực, những “…” trong thông điệp sẽ làtên lớp đầy đủmàjava
là tìm kiếm.
Vậy tại sao nó không thể tìm thấy lớp học?
Lý do số 1 – bạn đã mắc lỗi với đối số tên lớp
Nguyên nhân có thể đầu tiên là bạn có thể đã cung cấp tên lớp sai. (Hoặc … tên lớp đúng, nhưng ở dạng sai.) Xem xét ví dụ trên, đây là một loạt cáccách saiđể chỉ định tên lớp:
- Ví dụ # 1 – tên lớp đơn giản:
java ListUser
Khi lớp được khai báo trong một gói như vậy
com.acme.example
, thì bạn phải sử dụng tên lớp đầy đủbao gồmtên gói trongjava
lệnh; ví dụjava com.acme.example.ListUser
- Ví dụ # 2 – tên tệp hoặc tên đường dẫn thay vì tên lớp:
java ListUser.class java com/acme/example/ListUser.class
- Ví dụ # 3 – một tên lớp với vỏ không chính xác:
java com.acme.example.listuser
- Ví dụ # 4 – một lỗi đánh máy
java com.acme.example.mistuser
- Ví dụ # 5 – tên tệp nguồn (ngoại trừ Java 11 trở lên; xem bên dưới)
java ListUser.java
- Ví dụ # 6 – bạn quên hoàn toàn tên lớp
java lots of arguments
Lý do # 2 – đường dẫn lớp của ứng dụng được chỉ định không chính xác
Nguyên nhân có khả năng thứ hai là tên lớp là chính xác, nhưngjava
lệnh không thể tìm thấy lớp. Để hiểu điều này, bạn cần hiểu khái niệm về “classpath”. Điều này được giải thíchtốtbởi tài liệu của Oracle:
- Các
java
tài liệu lệnh - Đặt đường dẫn .
- Hướng dẫn Java – PATH và CLASSPATH
Vì vậy, nếu bạn đã chỉ định tên lớp một cách chính xác, điều tiếp theo cần kiểm tra là bạn đã chỉ định chính xác đường dẫn lớp:
- Đọc ba tài liệu liên kết ở trên. (Có … ĐỌC chúng! Điều quan trọng là một lập trình viên Java phảihiểuít nhất những điều cơ bản về cách các cơ chế đường dẫn Java hoạt động.)
- Nhìn vào dòng lệnh và / hoặc biến môi trường CLASSPATH có hiệu lực khi bạn chạy
java
lệnh. Kiểm tra xem tên thư mục và tên tệp JAR có đúng không. - Nếu có tên đường dẫntương đốitrong đường dẫn lớp, hãy kiểm tra xem chúng có giải quyết chính xác không … từ thư mục hiện tại có hiệu lực khi bạn chạy
java
lệnh. - Kiểm tra xem lớp (được đề cập trong thông báo lỗi) có thể được định vị trên đường dẫn lớphiệu quả.
- Lưu ý rằng cú pháp classpathkhácvới Windows so với Linux và Mac OS. (Dấu phân tách classpath nằm
;
trên Windows và:
trên các bộ phân loại khác. Nếu bạn sử dụng trình phân tách sai cho nền tảng của mình, bạn sẽ không nhận được thông báo lỗi rõ ràng. Thay vào đó, bạn sẽ nhận được một tệp hoặc thư mục không tồn tại trên đường dẫn sẽ bị bỏ qua trong âm thầm .)
Lý do # 2a – thư mục sai nằm trên đường dẫn lớp
Khi bạn đặt một thư mục trên đường dẫn lớp, nó sẽ tương ứng với thư mục gốc của không gian tên đủ điều kiện. Các lớp được đặt trong cấu trúc thư mục bên dưới gốc đó,bằng cách ánh xạ tên đủ điều kiện vào một tên đường dẫn. Vì vậy, ví dụ, nếu “/ usr / local / acme / class” nằm trên đường dẫn lớp, thì khi JVM tìm kiếm một lớp được gọicom.acme.example.Foon
, nó sẽ tìm tệp “. Class ” với tên đường dẫn này:
/usr/local/acme/classes/com/acme/example/Foon.class
Nếu bạn đã đặt “/ usr / local / acme / class / com / acme / example” trên đường dẫn lớp, thì JVM sẽ không thể tìm thấy lớp.
Lý do # 2b – đường dẫn thư mục con không khớp với FQN
Nếu các lớp FQN của bạn làcom.acme.example.Foon
, thì JVM sẽ tìm kiếm “Foon. Class” trong thư mục “com / acme / example”:
- Nếu cấu trúc thư mục của bạn không khớp với cách đặt tên gói theo mẫu ở trên, JVM sẽ không tìm thấy lớp của bạn.
- Nếu bạn cốđổi tênmột lớp bằng cách di chuyển nó, điều đó cũng sẽ thất bại … nhưng stacktrace ngoại lệ sẽ khác. Có trách nhiệm nói điều gì đó như thế này:
Caused by: java.lang.NoClassDefFoundError: <path> (wrong name: <name>)
bởi vì FQN trong tệp lớp không khớp với những gì trình tải lớp dự kiến sẽ tìm thấy.
Để đưa ra một ví dụ cụ thể, giả sử rằng:
- bạn muốn chạy
com.acme.example.Foon
lớp - đường dẫn tập tin đầy đủ là
/usr/local/acme/classes/com/acme/example/Foon.class
, - thư mục làm việc hiện tại của bạn là
/usr/local/acme/classes/com/acme/example/
,
sau đó:
# 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
Ghi chú:
- Các
-classpath
tùy chọn có thể được rút ngắn xuống còn-cp
trong hầu hết các phiên bản Java. Kiểm tra các mục thủ công tương ứng chojava
,javac
v.v. - Hãy suy nghĩ cẩn thận khi lựa chọn giữa tên đường dẫn tuyệt đối và tương đối trong đường dẫn lớp. Hãy nhớ rằng một tên đường dẫn tương đối có thể “phá vỡ” nếu thư mục hiện tại thay đổi.
Lý do # 2c – thiếu phụ thuộc từ đường dẫn lớp
Classpath cần bao gồm tất cả các lớpkhác(không phải hệ thống) mà ứng dụng của bạn phụ thuộc vào. (Các lớp hệ thống được đặt tự động và bạn hiếm khi cần quan tâm đến vấn đề này.) Để lớp chính tải chính xác, JVM cần tìm:
- chính lớp học
- tất cả các lớp và giao diện trong hệ thống phân cấp siêu lớp (ví dụ: xem lớp Java có trong đường dẫn lớp nhưng khởi động không thành công với Lỗi: Không thể tìm hoặc tải lớp chính )
- tất cả các lớp và giao diện được tham chiếu bằng các khai báo biến hoặc biến, hoặc gọi phương thức hoặc biểu thức truy cập trường.
(Lưu ý: các đặc tả JLS và JVM cho phép một số phạm vi để JVM tải các lớp “một cách lười biếng” và điều này có thể ảnh hưởng khi ném ngoại lệ trình nạp lớp.)
Lý do # 3 – lớp đã bị khai báo sai gói
Đôi khi xảy ra việc ai đó đặt tệp mã nguồn vào thư mục sai trong cây mã nguồn của họ hoặc họ bỏ qua phầnpackage
khai báo. Nếu bạn làm điều này trong một IDE, trình biên dịch của IDE sẽ cho bạn biết về điều này ngay lập tức. Tương tự như vậy nếu bạn sử dụng một công cụ xây dựng Java phong nha, công cụ này sẽ chạyjavac
theo cách sẽ phát hiện vấn đề. Tuy nhiên, nếu bạn xây dựng mã Java bằng tay, bạn có thể thực hiện theo cách mà trình biên dịch không nhận thấy vấn đề và tệp “. Class” kết quả không nằm ở vị trí mà bạn mong đợi.
Vẫn không thể tìm thấy vấn đề?
Có rất nhiều thứ để kiểm tra, và rất dễ bỏ lỡ một cái gì đó. Hãy thử thêm-Xdiag
tùy chọn vàojava
dòng lệnh (như điều đầu tiên saujava
). Nó sẽ đưa ra nhiều thứ khác nhau về tải lớp và điều này có thể cung cấp cho bạn manh mối về vấn đề thực sự là gì.
Ngoài ra, hãy xem xét các sự cố có thể xảy ra do sao chép và dán các ký tự vô hình hoặc không phải ASCII từ các trang web, tài liệu, v.v. Và xem xét “homoglyphs”, hai chữ cái hoặc ký hiệu trông giống nhau … nhưng không.
Cuối cùng, rõ ràng bạn có thể gặp phải vấn đề này nếu bạn cố khởi chạy từ tệp JAR có chữ ký không chính xác(META-INF/*.SF)
.
Cú pháp thay thế chojava
Có ba cú pháp thay thế cho các chương trình Java khởi chạy bằng cách sử dụngjava command
.
1) Cú pháp được sử dụng để khởi chạy tệp JAR “thực thi” như sau:
java [ <options> ] -jar <jar-file-name> [<arg> ...]
ví dụ
java -Xmx100m -jar /usr/local/acme-example/listuser.jar fred
Tên của lớp điểm đầu vào (nghĩa làcom.acme.example.ListUser
) và đường dẫn lớp được chỉ định trong MANIFEST của tệp JAR.
2) Cú pháp khởi chạy một ứng dụng từ một mô-đun (Java 9 trở lên) như sau:
java [ <options> ] --module <module>[/<mainclass>] [<arg> ...]
Tên của lớp entrypoint được xác định bởi<module>
chính nó, hoặc được đưa ra bởi tùy chọn<mainclass>
.
3) Từ Java 11 trở đi, bạn có thể biên dịch và chạy một tệp mã nguồn duy nhất và chạy nó với cú pháp sau:
java [ <options> ] <sourcefile> [<arg> ...]
trong đó (thường là) một tệp có hậu tố “.java”.
Để biết thêm chi tiết, vui lòng tham khảo tài liệu chính thức chojava
lệnh phát hành Java mà bạn đang sử dụng.
IDE
Một IDE Java điển hình có hỗ trợ để chạy các ứng dụng Java trong chính JVM IDE hoặc trong một JVM con. Chúngthườngmiễn dịch với ngoại lệ cụ thể này, vì IDE sử dụng các cơ chế riêng của nó để xây dựng đường dẫn lớp thời gian chạy, xác định lớp chính và tạojava
dòng lệnh.
Tuy nhiên vẫn có thể xảy ra ngoại lệ này, nếu bạn làm những việc phía sau IDE. Ví dụ, nếu trước đây bạn đã thiết lập Trình khởi chạy ứng dụng cho ứng dụng Java của mình trong Eclipse và sau đó bạn đã di chuyển tệp JAR chứa lớp “chính” sang một vị trí khác trong hệ thống tệpmà không thông báo cho Eclipse, Eclipse sẽ vô tình khởi chạy JVM với một classpath không chính xác.
Nói tóm lại, nếu bạn gặp vấn đề này trong IDE, hãy kiểm tra những thứ như trạng thái IDE cũ, tham chiếu dự án bị hỏng hoặc cấu hình trình khởi chạy bị hỏng.
IDE cũng có thể bị nhầm lẫn. IDE là những phần mềm cực kỳ phức tạp bao gồm nhiều phần tương tác. Nhiều trong số các phần này áp dụng các chiến lược bộ nhớ đệm khác nhau để làm cho toàn bộ IDE đáp ứng. Điều này đôi khi có thể đi sai, và một triệu chứng có thể là vấn đề khi khởi chạy ứng dụng. Nếu bạn nghi ngờ điều này có thể xảy ra, đáng để thử những thứ khác như khởi động lại IDE của bạn, xây dựng lại dự án
Nguồn:
- //wiki.tino.org/sua-loi-error-could-not-find-or-load-main-class/
- //qastack.vn/programming/18093928/what-does-could-not-find-or-load-main-class-mean