Tôi nhận được NoClassDefFoundError
khi tôi chạy ứng dụng Java của mình. Điều gì thường là nguyên nhân của điều này?
Tôi nhận được NoClassDefFoundError
khi tôi chạy ứng dụng Java của mình. Điều gì thường là nguyên nhân của điều này?
Câu trả lời:
Điều này được gây ra khi có một tệp lớp mà mã của bạn phụ thuộc vào và nó có mặt tại thời gian biên dịch nhưng không được tìm thấy trong thời gian chạy. Tìm kiếm sự khác biệt trong thời gian xây dựng và các đường dẫn lớp thời gian chạy.
Mặc dù có thể điều này là do sự không khớp của lớp giữa thời gian biên dịch và thời gian chạy, nhưng nó không nhất thiết phải đúng.
Điều quan trọng là phải giữ hai hoặc ba ngoại lệ khác nhau trong đầu chúng ta trong trường hợp này:
java.lang.ClassNotFoundException
Ngoại lệ này chỉ ra rằng lớp không được tìm thấy trên đường dẫn lớp. Điều này chỉ ra rằng chúng tôi đã cố tải định nghĩa lớp và lớp không tồn tại trên đường dẫn lớp.
java.lang.NoClassDefFoundError
Ngoại lệ này chỉ ra rằng JVM đã xem xét cấu trúc dữ liệu định nghĩa lớp bên trong của nó để định nghĩa một lớp và không tìm thấy nó. Điều này khác với việc nói rằng nó không thể được tải từ classpath. Thông thường, điều này chỉ ra rằng trước đây chúng tôi đã cố tải một lớp từ đường dẫn lớp, nhưng vì một số lý do không thành công - bây giờ chúng tôi đang cố gắng sử dụng lại lớp đó (và do đó cần phải tải nó, vì lần trước nó đã thất bại), nhưng chúng tôi ' thậm chí sẽ không thử tải nó, bởi vì chúng tôi đã không tải nó sớm hơn (và nghi ngờ hợp lý rằng chúng tôi sẽ lại thất bại). Lỗi trước đó có thể là ClassNotFoundException hoặc ExceptionInInialialError (chỉ ra lỗi trong khối khởi tạo tĩnh) hoặc bất kỳ vấn đề nào khác. Vấn đề là, NoClassDefFoundError không nhất thiết là một vấn đề về đường dẫn.
Error: Could not find or load main class
, nó sẽ được phân loại theo loại lỗi nào?
Đây là mã để minh họa java.lang.NoClassDefFoundError
. Xin vui lòng xem câu trả lời của Jared để được giải thích chi tiết.
NoClassDefFoundErrorDemo.java
public class NoClassDefFoundErrorDemo {
public static void main(String[] args) {
try {
// The following line would throw ExceptionInInitializerError
SimpleCalculator calculator1 = new SimpleCalculator();
} catch (Throwable t) {
System.out.println(t);
}
// The following line would cause NoClassDefFoundError
SimpleCalculator calculator2 = new SimpleCalculator();
}
}
SimpleCalculator.java
public class SimpleCalculator {
static int undefined = 1 / 0;
}
SimpleCalculator
sau khi chia cho 0? Có ai đó có một tài liệu tham khảo cho các tài liệu chính thức cho hành vi này?
new SimpleCalculator()
được gọi, bạn nhận được một ExceptionInitializerError với nguyên nhân là do ArithaturesException. Lần thứ hai bạn gọi, new SimpleCalculator()
bạn nhận được NoClassDefFoundError thuần túy như mọi thứ khác. Vấn đề là bạn có thể nhận được NoClassDefFoundError vì một lý do khác ngoài SimpleCalculator. Class không có trên đường dẫn lớp khi chạy.
NoClassDefFoundError trong Java
Định nghĩa:
Máy ảo Java không thể tìm thấy một lớp cụ thể trong thời gian chạy có sẵn tại thời gian biên dịch.
Nếu một lớp đã có mặt trong thời gian biên dịch nhưng không có sẵn trong java classpath trong thời gian chạy.
Ví dụ:
Một ví dụ đơn giản về NoClassDefFoundError là lớp thuộc về tệp JAR bị thiếu hoặc JAR không được thêm vào classpath hoặc đôi khi tên của jar đã bị thay đổi bởi một người như trong trường hợp của tôi, một trong những đồng nghiệp của tôi đã đổi tibco.jar thành tibco_v3.jar và chương trình là thất bại với java.lang.NoClassDefFoundError và tôi đã tự hỏi điều gì sai.
Chỉ cần thử chạy với tùy chọn classpath rõ ràng với đường dẫn lớp mà bạn nghĩ sẽ hoạt động và nếu nó hoạt động thì đó là một dấu hiệu ngắn chắc chắn rằng ai đó đang ghi đè đường dẫn java.
Phương pháp khả thi:
Tài nguyên:
Tôi đã thấy rằng đôi khi tôi gặp lỗi NoClassDefFound khi mã được biên dịch với phiên bản không tương thích của lớp được tìm thấy trong thời gian chạy. Ví dụ cụ thể tôi nhớ là với thư viện trục apache. Thực tế, có 2 phiên bản trên classpath thời gian chạy của tôi và nó đã chọn phiên bản lỗi thời và không tương thích và không phải là phiên bản chính xác, gây ra lỗi NoClassDefFound. Đây là trong một ứng dụng dòng lệnh nơi tôi đang sử dụng một lệnh tương tự như thế này.
set classpath=%classpath%;axis.jar
Tôi đã có thể lấy nó để chọn phiên bản phù hợp bằng cách sử dụng:
set classpath=axis.jar;%classpath%;
Đây là giải pháp tốt nhất tôi tìm thấy cho đến nay.
Giả sử chúng ta có một gói được gọi là org.mypackage
chứa các lớp:
và các tệp xác định gói này được lưu trữ vật lý trong thư mục D:\myprogram
(trên Windows) hoặc /home/user/myprogram
(trên Linux).
Cấu trúc tập tin sẽ trông như thế này:
Khi chúng tôi gọi Java, chúng tôi chỉ định tên của ứng dụng sẽ chạy : org.mypackage.HelloWorld
. Tuy nhiên, chúng ta cũng phải cho Java biết nơi tìm các tệp và thư mục xác định gói của chúng ta. Vì vậy, để khởi chạy chương trình, chúng ta phải sử dụng lệnh sau:
Tôi đã sử dụng Spring Framework với Maven và đã khắc phục lỗi này trong dự án của mình.
Có một lỗi thời gian chạy trong lớp. Tôi đã đọc một thuộc tính là số nguyên, nhưng khi nó đọc giá trị từ tệp thuộc tính, giá trị của nó là gấp đôi.
Spring đã không cho tôi một dấu vết ngăn xếp đầy đủ về dòng thời gian chạy thất bại. Nó chỉ đơn giản nói NoClassDefFoundError
. Nhưng khi tôi thực thi nó như là một ứng dụng Java nguyên gốc (lấy nó ra khỏi MVC), thì ExceptionInInitializerError
đó là nguyên nhân thực sự và đó là cách tôi truy tìm lỗi.
Câu trả lời của @ xli đã cho tôi cái nhìn sâu sắc về những gì có thể sai trong mã của tôi.
NoClassDefFoundError
thực ra là do ExceptionInInitalizerError
, nguyên nhân là do DateTimeParseException
). Đó là một chút sai lệch, phải không? Tôi biết có lẽ họ có lý do để biến nó thành như vậy, nhưng thật tuyệt khi có ít nhất một gợi ý nhỏ, đó NoClassDefFoundError
là kết quả của một ngoại lệ khác, mà không cần phải suy luận ra. Chỉ cần ném ExceptionInInitializerError
một lần nữa sẽ rõ ràng hơn nhiều. Đôi khi kết nối giữa hai người có thể không rõ ràng.
Tôi nhận được NoClassFoundError khi các lớp được tải bởi trình tải lớp thời gian chạy không thể truy cập các lớp đã được tải bởi trình tải gốc java. Vì các trình nạp lớp khác nhau nằm trong các miền bảo mật khác nhau (theo java), jvm sẽ không cho phép các lớp đã được tải bởi trình tải gốc được giải quyết trong không gian địa chỉ của trình tải thời gian chạy.
Chạy chương trình của bạn với 'java -javaagent: tracer.jar [ARGS java CỦA BẠN]'
Nó tạo ra kết quả hiển thị lớp được tải và env của trình tải đã tải lớp đó. Đó là dấu vết rất hữu ích tại sao một lớp học không thể được giải quyết.
// ClassLoaderTracer.java
// From: https://blogs.oracle.com/sundararajan/entry/tracing_class_loading_1_5
import java.lang.instrument.*;
import java.security.*;
// manifest.mf
// Premain-Class: ClassLoadTracer
// jar -cvfm tracer.jar manifest.mf ClassLoaderTracer.class
// java -javaagent:tracer.jar [...]
public class ClassLoadTracer
{
public static void premain(String agentArgs, Instrumentation inst)
{
final java.io.PrintStream out = System.out;
inst.addTransformer(new ClassFileTransformer() {
public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
String pd = (null == protectionDomain) ? "null" : protectionDomain.getCodeSource().toString();
out.println(className + " loaded by " + loader + " at " + new java.util.Date() + " in " + pd);
// dump stack trace of the thread loading class
Thread.dumpStack();
// we just want the original .class bytes to be loaded!
// we are not instrumenting it...
return null;
}
});
}
}
Một trường hợp thú vị mà bạn có thể thấy rất nhiều NoClassDefFoundErrors
là khi bạn:
throw
một RuntimeException
trong static
khối của lớp học của bạnExample
Example
static class Example {
static {
thisThrowsRuntimeException();
}
}
static class OuterClazz {
OuterClazz() {
try {
new Example();
} catch (Throwable ignored) { //simulating catching RuntimeException from static block
// DO NOT DO THIS IN PRODUCTION CODE, THIS IS JUST AN EXAMPLE in StackOverflow
}
new Example(); //this throws NoClassDefFoundError
}
}
NoClassDefError
sẽ được ném kèm theo ExceptionInInitializerError
từ khối tĩnh RuntimeException
.
Đây là trường hợp đặc biệt quan trọng khi bạn nhìn thấy NoClassDefFoundErrors
trong KIỂM TRA ĐƠN VỊ .
Theo cách bạn đang "chia sẻ" việc static
thực thi khối giữa các lần kiểm tra, nhưng lần đầu tiên ExceptionInInitializerError
sẽ chỉ trong một trường hợp kiểm tra. Cái đầu tiên sử dụng Example
lớp có vấn đề . Các trường hợp kiểm tra khác sử dụng Example
lớp sẽ chỉ ném NoClassDefFoundErrors
.
Kỹ thuật dưới đây đã giúp tôi nhiều lần:
System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());
trong đó TheNoDefFoundClass là lớp có thể bị "mất" do ưu tiên cho phiên bản cũ hơn của cùng một thư viện được sử dụng bởi chương trình của bạn. Điều này thường xảy ra với các trường hợp, khi phần mềm máy khách đang được triển khai vào một thùng chứa chiếm ưu thế, được trang bị bộ nạp lớp riêng và hàng tấn phiên bản cổ của hầu hết các lib phổ biến.
Trong trường hợp bạn đã tạo mã (EMF, v.v.), có thể có quá nhiều trình khởi tạo tĩnh tiêu tốn tất cả không gian ngăn xếp.
Xem câu hỏi về Stack Overflow Làm thế nào để tăng kích thước ngăn xếp Java? .
NoClassDefFoundError
cũng có thể xảy ra khi trình khởi tạo tĩnh cố gắng tải gói tài nguyên không có sẵn trong thời gian chạy, ví dụ: tệp thuộc tính mà lớp bị ảnh hưởng cố tải từ META-INF
thư mục, nhưng không có ở đó. Nếu bạn không bắt NoClassDefFoundError
, đôi khi bạn sẽ không thể thấy dấu vết ngăn xếp đầy đủ; Để khắc phục điều này, bạn có thể tạm thời sử dụng một catch
mệnh đề cho Throwable
:
try {
// Statement(s) that cause the affected class to be loaded
} catch (Throwable t) {
Logger.getLogger("<logger-name>").info("Loading my class went wrong", t);
}
for example a properties file that the affected class tries to load from the META-INF directory
. Điều này thực sự đã xảy ra với tôi và tôi đã có thể giải quyết NoClassDefFoundError
bằng cách thêm tệp thuộc tính bị thiếu. Tôi đã thêm câu trả lời này chính xác bởi vì người ta sẽ không mong đợi lỗi này trong các trường hợp được đề cập.
static
khởi tạo ... điều này đã kích hoạt một ngoại lệ không được kiểm tra và gây ra lớp init thất bại. Bất kỳ ngoại lệ không được kiểm soát lan truyền từ khởi tạo tĩnh sẽ làm điều đó.
static
khởi tạo thất bại ), tôi sẽ thấy thú vị khi xem một ví dụ thực tế (tức là MCVE) thể hiện hành vi.
Tôi đã gặp lỗi này khi thêm phụ thuộc Maven của một mô-đun khác vào dự án của mình, vấn đề cuối cùng đã được giải quyết bằng cách thêm -Xss2m
vào tùy chọn JVM của chương trình của tôi (Theo mặc định là một megabyte kể từ JDK5.0). Người ta tin rằng chương trình không có đủ ngăn xếp để tải lớp.
Nếu ai đó đến đây vì java.lang.NoClassDefFoundError: org/apache/log4j/Logger
lỗi, trong trường hợp của tôi, nó được tạo ra vì tôi đã sử dụng log4j 2 (nhưng tôi đã không thêm tất cả các tệp đi kèm với nó) và một số thư viện phụ thuộc đã sử dụng log4j 1. Giải pháp là thêm Log4j Cầu 1.x: jar log4j-1.2-api-<version>.jar
đi kèm với log4j 2. Thông tin thêm trong quá trình di chuyển log4j 2 .
Trong trường hợp của tôi, vấn đề là Eclipse không có khả năng phân biệt giữa hai bản sao khác nhau của cùng một dự án. Tôi có một khóa trên thân cây (điều khiển phiên bản SVN) và một cái khác hoạt động trong một nhánh tại một thời điểm. Tôi đã thử một thay đổi trong bản sao làm việc như một trường hợp thử nghiệm JUnit, bao gồm trích xuất một lớp bên trong riêng thành một lớp công khai và trong khi nó đang hoạt động, tôi mở bản sao khác của dự án để xem xét một số khác một phần của mã cần thay đổi. Tại một số điểm, các cửa sổ NoClassDefFoundError
bật lên phàn nàn rằng lớp bên trong tư nhân không có ở đó; bấm đúp vào theo dõi ngăn xếp đưa tôi đến tệp nguồn trong bản sao dự án sai.
Đóng bản sao thân của dự án và chạy trường hợp thử nghiệm một lần nữa đã thoát khỏi vấn đề.
Lỗi này có thể do các yêu cầu phiên bản Java không được kiểm tra .
Trong trường hợp của tôi, tôi đã có thể khắc phục lỗi này, trong khi xây dựng một dự án nguồn mở cấu hình cao, bằng cách chuyển từ Java 9 sang Java 8 bằng SDKMAN! .
sdk list java
sdk install java 8u152-zulu
sdk use java 8u152-zulu
Sau đó thực hiện cài đặt sạch như mô tả dưới đây.
Khi sử dụng Maven làm công cụ xây dựng của bạn, đôi khi rất hữu ích - và thường là hài lòng, để thực hiện bản dựng 'cài đặt' sạch với thử nghiệm bị vô hiệu hóa .
mvn clean install -DskipTests
Bây giờ mọi thứ đã được xây dựng và cài đặt, bạn có thể tiếp tục và chạy thử nghiệm.
mvn test
Tôi đã gặp lỗi NoClassDefFound khi tôi không xuất một lớp trên tab "Đặt hàng và Xuất" trong Đường dẫn xây dựng Java của dự án. Đảm bảo đặt dấu kiểm vào tab "Đặt hàng và xuất" của bất kỳ phụ thuộc nào bạn thêm vào đường dẫn xây dựng của dự án. Xem cảnh báo Eclipse: XXXXXXXXXXX.jar sẽ không được xuất hoặc xuất bản. Thời gian chạy ClassNotFoundExceptions có thể dẫn đến .
Trong trường hợp của tôi, tôi đã gặp lỗi này do sự không phù hợp trong các phiên bản JDK. Khi tôi cố chạy ứng dụng từ Intelij, nó không hoạt động nhưng sau đó chạy nó từ dòng lệnh hoạt động. Điều này là do Intelij đã cố chạy nó với JDK Java 11 đã được thiết lập nhưng trên dòng lệnh mà nó đang chạy với JDK Java 8. Sau khi chuyển đổi cài đặt đó trong Tệp> Cấu trúc dự án> Cài đặt dự án> SDK dự án, nó hoạt động với tôi.
Mọi người đều nói ở đây về một số công cụ cấu hình Java, các vấn đề về JVM, v.v. Ứng dụng khởi động mùa xuân).
Tôi đã gặp một vấn đề thú vị khi NoClassDefFoundError trong JavaEE làm việc với máy chủ Liberty. Tôi đã sử dụng các bộ điều hợp tài nguyên IMS và server.xml của tôi đã có bộ điều hợp tài nguyên cho imsudbJXA.rar. Khi tôi thêm bộ điều hợp mới cho imsudbXA.rar, tôi sẽ bắt đầu gặp lỗi này cho các đối tượng ví dụ cho DLIException, IMSConnectionSpec hoặc SQLInteractionSpec. Tôi không thể hiểu tại sao nhưng tôi đã giải quyết nó bằng cách tạo serverDB mới cho công việc của mình chỉ bằng imsudbXA.rar. Tôi chắc chắn rằng việc sử dụng nhiều bộ điều hợp tài nguyên trong server.xml là ổn, tôi chỉ không có thời gian để xem xét điều đó.
Java không thể tìm thấy lớp A trong thời gian chạy. Lớp A nằm trong dự án maven ArtClient từ một không gian làm việc khác. Vì vậy, tôi đã nhập ArtClient vào dự án Eclipse của mình. Hai dự án của tôi đã sử dụng ArtClient làm phụ thuộc. Tôi đã thay đổi tham chiếu thư viện thành tham chiếu dự án cho những cái này (Đường dẫn xây dựng -> Cấu hình đường dẫn xây dựng).
Và vấn đề đã biến mất.
Tôi đã có cùng một vấn đề, và tôi đã chứng khoán trong nhiều giờ.
Tôi tìm thấy giải pháp. Trong trường hợp của tôi, có phương thức tĩnh được xác định do đó. JVM không thể tạo đối tượng khác của lớp đó.
Ví dụ,
private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http");
Tôi đã nhận được thông báo này sau khi xóa hai tệp khỏi thư viện SRC và khi tôi mang chúng trở lại, tôi vẫn thấy thông báo lỗi này.
Giải pháp của tôi là: Khởi động lại Eclipse. Kể từ đó tôi không thấy tin nhắn này nữa :-)
Hãy chắc chắn rằng điều này phù hợp trong module:app
và module:lib
:
android {
compileSdkVersion 23
buildToolsVersion '22.0.1'
packagingOptions {
}
defaultConfig {
minSdkVersion 17
targetSdkVersion 23
versionCode 11
versionName "2.1"
}
{s
và hai }
). Bạn có thể sửa nó không?