Jaka jest różnica między NoClassDefFoundError
i ClassNotFoundException
?
Co powoduje ich wyrzucenie? Jak można je rozwiązać?
Często napotykam te rzuty podczas modyfikowania istniejącego kodu, aby zawierał nowe pliki jar. Uderzyłem je zarówno po stronie klienta, jak i po stronie serwera dla aplikacji Java dystrybuowanej za pośrednictwem WebStart.
Możliwe przyczyny, z którymi się zetknąłem:
- pakiety nie są zawarte
build.xml
po stronie klienta kodu - brakuje ścieżki klas środowiska wykonawczego dla nowych używanych słoików
- wersja jest w konflikcie z poprzednim słoikiem
Kiedy spotykam je dzisiaj, stosuję podejście oparte na analizie błędów i błędów, aby wszystko działało. Potrzebuję więcej jasności i zrozumienia.
-verbose
(np.-verbose:class -verbose:jni
) Pomaga - ale mogsie informuje poniżej ich odpowiedź, że nie zapewnia to żadnych dodatkowych użytecznych informacji :(Odpowiedzi:
Różnica w stosunku do specyfikacji Java API jest następująca.
Dla
ClassNotFoundException
:Dla
NoClassDefFoundError
:Wygląda więc na to, że
NoClassDefFoundError
występuje, gdy źródło zostało pomyślnie skompilowane, ale w czasie wykonywaniaclass
nie znaleziono wymaganych plików. Może się tak zdarzyć w dystrybucji lub produkcji plików JAR, w których nie wszystkie wymaganeclass
pliki zostały uwzględnione.Jak dla
ClassNotFoundException
wydaje się, że może to wynikać z starając się odblaskowe połączeń do klas w czasie wykonywania, ale zajęcia program próbuje rozmowy jest nie istnieje.Różnica między nimi polega na tym, że jeden jest drugim,
Error
a drugi jestException
. ZNoClassDefFoundError
jestError
i wynika z tego, że wirtualna maszyna Java ma problemy ze znalezieniem oczekiwanej klasy. Program, który miał działać w czasie kompilacji, nie może zostać uruchomiony z powodu brakuclass
plików lub nie jest taki sam, jak został utworzony lub napotkany w czasie kompilacji. Jest to dość krytyczny błąd, ponieważ JVM nie może zainicjować programu.Z drugiej strony
ClassNotFoundException
jest toException
, więc jest nieco oczekiwane i jest czymś, co można odzyskać. Używanie refleksji może być podatne na błędy (ponieważ istnieją pewne oczekiwania, że rzeczy mogą nie pójść zgodnie z oczekiwaniami. Nie ma sprawdzania czasu kompilacji, aby sprawdzić, czy istnieją wszystkie wymagane klasy, więc wszelkie problemy ze znalezieniem pożądanych klas pojawią się w czasie wykonywania .źródło
NoClassDefFoundError
zwykle występuje, gdy występuje problem (zgłoszony wyjątek) z inicjalizacją bloku statycznego lub pól statycznych, więc klasy nie można pomyślnie zainicjować.Error
a drugi jestException
. :)ClassNotFoundException jest generowany, gdy zgłoszona klasa nie zostanie znaleziona przez ClassLoader. Zazwyczaj oznacza to brak klasy w CLASSPATH. Może to również oznaczać, że dana klasa próbuje zostać załadowana z innej klasy, która została załadowana do nadrzędnego modułu ładującego klasy, a zatem klasa z podrzędnego modułu ładującego klasy nie jest widoczna. Czasami ma to miejsce w przypadku pracy w bardziej złożonych środowiskach, takich jak serwer aplikacji (WebSphere jest niesławny z powodu takich problemów z modułem ładującym klasy).
Ludzie często mylą się
java.lang.NoClassDefFoundError
z tym,java.lang.ClassNotFoundException
że istnieje ważne rozróżnienie. Na przykład wyjątek (tak naprawdę błądjava.lang.NoClassDefFoundError
jest podklasą java.lang.Error)nie oznacza, że klasy ActiveMQConnectionFactory nie ma w CLASSPATH. W rzeczywistości jest wręcz przeciwnie. Oznacza to, że klasa ActiveMQConnectionFactory została znaleziona przez ClassLoader, jednak podczas próby załadowania klasy wystąpił błąd podczas odczytu definicji klasy. Zwykle dzieje się tak, gdy dana klasa ma statyczne bloki lub elementy, które używają Klasy, która nie została znaleziona przez ClassLoader. Aby więc znaleźć winowajcę, przejrzyj źródło danej klasy (w tym przypadku ActiveMQConnectionFactory) i poszukaj kodu za pomocą bloków statycznych lub elementów statycznych. Jeśli nie masz dostępu do źródła, po prostu dekompiluj je za pomocą JAD.
Podczas sprawdzania kodu powiedz, że znajdujesz wiersz kodu jak poniżej, upewnij się, że klasa SomeClass znajduje się w Twojej CLASSPATH.
Wskazówka: aby dowiedzieć się, do którego słoika należy klasa, możesz skorzystać ze strony jarFinder. Pozwala to określić nazwę klasy za pomocą symboli wieloznacznych i wyszukuje klasę w bazie danych słoików. jarhoo pozwala robić to samo, ale nie jest już darmowy.
Jeśli chcesz zlokalizować słoik, do którego należy klasa w ścieżce lokalnej, możesz użyć narzędzia takiego jak jarscan ( http://www.inetfeedback.com/jarscan/ ). Po prostu określ klasę, którą chcesz zlokalizować, i ścieżkę do katalogu głównego, w której chcesz, aby zaczęła szukać klasy w słoikach i plikach zip.
źródło
NoClassDefFoundError
jest zasadniczo błędem powiązania. Występuje, gdy próbujesz utworzyć instancję obiektu (statycznie z „nowym”) i nie można go znaleźć podczas kompilacji.ClassNotFoundException
jest bardziej ogólny i stanowi wyjątek czasu wykonywania, gdy próbujesz użyć klasy, która nie istnieje. Na przykład, parametr w funkcji akceptuje interfejs i ktoś przechodzi do klasy, która implementuje ten interfejs, ale nie masz dostępu do klasy. Obejmuje również przypadki dynamicznego ładowania klas, takie jak używanieloadClass()
lubClass.forName()
.źródło
NoClassDefFoundError (NCDFE) ma miejsce, gdy kod uruchamia „new Y ()” i nie może znaleźć klasy Y.
Być może po prostu brakuje Y w module ładującym klasy, jak sugerują inne komentarze, ale może być tak, że klasa Y nie jest podpisana lub ma nieprawidłowy podpis, lub że Y jest ładowany przez inny moduł ładujący klasy niewidoczny dla Twojego kodu lub nawet, że Y zależy od Z, którego nie można załadować z żadnego z powyższych powodów.
Jeśli tak się stanie, wówczas JVM zapamięta wynik ładowania X (NCDFE) i po prostu wyrzuci nowy NCDFE za każdym razem, gdy poprosisz o Y, bez podania przyczyny:
zapisz gdzieś jako a.java
Kod po prostu próbuje dwa razy utworzyć nową klasę „b”, poza tym nie ma żadnych błędów i nic nie robi.
Skompiluj kod
javac a.java
, a następnie uruchom a, wywołującjava -cp . a
- powinien po prostu wydrukować dwa wiersze tekstu i powinien działać poprawnie bez błędów.Następnie usuń plik „a $ b.class” (lub wypełnij go śmieciami lub skopiuj nad nim klasę a.class), aby zasymulować brakującą lub uszkodzoną klasę. Oto co się dzieje:
Pierwsze wywołanie powoduje wyjątek ClassNotFoundException (generowany przez moduł ładujący klasy, gdy nie może znaleźć klasy), który musi być zawinięty w niezaznaczone NoClassDefFoundError, ponieważ kod, o którym mowa (
new b()
) powinien po prostu działać.Druga próba oczywiście również się nie powiedzie, ale jak widać zawinięty wyjątek już nie istnieje, ponieważ ClassLoader wydaje się pamiętać, że nie udało się załadować klas. Widzisz tylko NCDFE bez absolutnie żadnego pojęcia, co tak naprawdę się wydarzyło.
Więc jeśli kiedykolwiek zobaczysz NCDFE bez podstawowej przyczyny, musisz sprawdzić, czy możesz prześledzić do pierwszego załadowania klasy, aby znaleźć przyczynę błędu.
źródło
-verbose
jakąś podobną opcją w zależności od konkretnej maszyny JVM? Prawdopodobnie-verbose:class
może-verbose:class:jni
przy użyciu JNI, ale nie jestem pewien co do składni. Jeśli jest to przydatne, być może możesz pokazać wyniki.-verbose:class
nie-verbose:jni
przekazuj żadnych dodatkowych danych wyjściowych dotyczących brakującej klasy.-verbose:class:jni
jest źle: trzeba określić dwie osobne opcje-verbose:class -verbose:jni
Od http://www.javaroots.com/2013/02/classnotfoundexception-vs.html :
ClassNotFoundException
: występuje, gdy moduł ładujący klasy nie może znaleźć wymaganej klasy na ścieżce klasy. Zasadniczo powinieneś sprawdzić ścieżkę swojej klasy i dodać klasę do ścieżki klasy.NoClassDefFoundError
: trudniej jest debugować i znaleźć przyczynę. Jest to generowane, gdy w czasie kompilacji obecne są wymagane klasy, ale w czasie wykonywania klasy są zmieniane lub usuwane lub statyczna inicjalizacja klasy generuje wyjątki. Oznacza to, że ładowana klasa jest obecna w ścieżce klas, ale jedna z klas wymaganych przez tę klasę została usunięta lub nie można jej załadować przez kompilator. Powinieneś zobaczyć klasy zależne od tej klasy.Przykład :
Teraz po skompilowaniu obu klas, jeśli usuniesz plik Test1.class i uruchomisz klasę testową, to rzuci
ClassNotFoundException
: generowany, gdy aplikacja próbuje załadować klasę poprzez swoją nazwę, ale nie można znaleźć definicji klasy o podanej nazwie.NoClassDefFoundError
: wyrzucany, jeśli wirtualna maszyna Java próbuje załadować definicję klasy i nie można znaleźć definicji klasy.źródło
-verbose
jakąś podobną opcją w zależności od konkretnej maszyny JVM? Prawdopodobnie-verbose:class
może-verbose:class:jni
przy użyciu JNI, ale nie jestem pewien co do składni.-verbose:class:jni
jest źle, ale można przejść dwie oddzielne opcje:-verbose:class -verbose:jni
.Są blisko spokrewnieni. Zgłaszane
ClassNotFoundException
jest, gdy Java szukała określonej klasy według nazwy i nie mogła jej pomyślnie załadować.NoClassDefFoundError
Jest generowany, gdy Java poszedł szuka klasy, która była związana do jakiegoś istniejącego kodu, ale nie mógł znaleźć dla jednej lub innego powodu (np błędne ścieżki klasy, zła wersja Java, niewłaściwej wersji biblioteki) i jest dokładnie śmiertelne ponieważ wskazuje, że coś poszło nie tak.Jeśli masz tło C, CNFE jest jak awaria
dlopen()
/dlsym()
a NCDFE stanowi problem z łącznikiem; w drugim przypadku odnośne pliki klas nigdy nie powinny były zostać skompilowane w konfiguracji, w której próbujesz ich użyć.źródło
Przykład 1:
Jeśli
com/example/Class1
nie istnieje w żadnej z klas, to rzucaClassNotFoundException
.Przykład 2:
Jeśli
com/example/Class2
istniał podczas kompilacji B, ale nie został znaleziony podczas wykonywania, to rzucaNoClassDefFoundError
.Oba są wyjątkami czasu wykonywania.
źródło
ClassNotFoundException jest generowany, gdy następuje próba załadowania klasy przez odwołanie do niej za pomocą ciągu znaków. Na przykład parametr to w Class.forName () jest ciągiem, co podnosi potencjał przekazywania niepoprawnych nazw binarnych do modułu ładującego klasy.
ClassNotFoundException jest zgłaszany, gdy napotkamy potencjalnie niepoprawną nazwę binarną; na przykład, jeśli nazwa klasy ma znak „/”, musisz uzyskać wyjątek ClassNotFoundException. Jest także generowany, gdy bezpośrednio odwoływana klasa nie jest dostępna w ścieżce klasy.
Z drugiej strony generowany jest NoClassDefFoundError
Krótko mówiąc, NoClassDefFoundError jest zwykle generowany przez nowe () instrukcje lub wywołania metod, które ładują wcześniej nieobecną klasę (w przeciwieństwie do łańcuchowego ładowania klas dla ClassNotFoundException), gdy moduł ładujący klasy nie jest w stanie znaleźć lub załadować definicji klasy ( s).
Ostatecznie do implementacji ClassLoader należy zgłoszenie wystąpienia wyjątku ClassNotFoundException, gdy nie można załadować klasy. Wykonuje to większość niestandardowych implementacji modułu ładującego klasy, ponieważ rozszerzają one URLClassLoader. Zazwyczaj moduły ładujące klasy nie rzucają jawnie NoClassDefFoundError na żadną implementację metody - ten wyjątek jest zwykle zgłaszany z maszyny JVM w kompilatorze HotSpot, a nie przez sam moduł ładujący klasy.
źródło
Różnica między ClassNotFoundException Vs NoClassDefFoundError
źródło
Wyjątek: wyjątki występują podczas wykonywania programu. Programista może obsłużyć te wyjątki, próbując złapać blok. Mamy dwa rodzaje wyjątków. Sprawdzono wyjątek, który zgłasza się w czasie kompilacji. Wyjątki czasu wykonywania zgłaszane w czasie wykonywania, wyjątki te zwykle występują z powodu złego programowania.
Błąd: W ogóle nie są to wyjątki, wykracza to poza zakres programisty. Błędy te są zwykle zgłaszane przez JVM.
Źródło obrazu
Różnica:
Klasa nie znaleziono wyjątku:
ClassNotFoundException
.ClassNotFoundException
to sprawdzony wyjątek wywodzący się bezpośrednio zjava.lang.Exception
klasy i należy dla niego zapewnić jawną obsługęClassNotFoundException
pojawia się, gdy następuje jawne załadowanie klasy poprzez podanie nazwy klasy w czasie wykonywania przy użyciu ClassLoader.loadClass (), Class.forName () i ClassLoader.findSystemClass ().NoClassDefFoundError:
NoClassDefFoundError
.NoClassDefFoundError
jest błędem wywodzącym się zLinkageError
klasy, który służy do wskazywania przypadków błędów, w których klasa jest zależna od innej klasy, a klasa ta zmieniła się niekompatybilnie po kompilacji.NoClassDefFoundError
jest wynikiem niejawnego ładowania klasy z powodu wywołania metody z tej klasy lub dowolnego dostępu do zmiennej.Podobieństwa:
NoClassDefFoundError
iClassNotFoundException
są związane z niedostępnością klasy w czasie wykonywania.ClassNotFoundException
iNoClassDefFoundError
związane są ścieżki klasy Java.źródło
Biorąc pod uwagę działania sussystem modułu ładującego klasy:
To jest artykuł, który bardzo pomógł mi zrozumieć różnicę: http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html
Zatem wyjątek ClassNotFoundException jest podstawową przyczyną NoClassDefFoundError .
A NoClassDefFoundError jest szczególnym przypadkiem błędu ładowania typu, który występuje na etapie łączenia .
źródło
Dodaj jeden możliwy powód w praktyce:
W praktyce błąd może być rzucany w ciszy , np. Przesyłasz zadanie czasomierza, aw zadaniu czasomierza wyrzuca błąd , podczas gdy w większości przypadków twój program tylko przechwytuje wyjątek . Następnie główna pętla timera kończy się bez żadnych informacji. Podobny błąd do NoClassDefFoundError to ExceptionInInitializerError , gdy inicjator statyczny lub inicjator zmiennej statycznej zgłasza wyjątek.
źródło
ClassNotFoundException to sprawdzony wyjątek, który występuje, gdy mówimy JVM, aby załadowała klasę za pomocą nazwy swojego ciągu przy użyciu metod Class.forName () lub ClassLoader.findSystemClass () lub ClassLoader.loadClass () i wspomniana klasa nie została znaleziona w ścieżce klasy.
W większości przypadków ten wyjątek występuje podczas próby uruchomienia aplikacji bez aktualizacji ścieżki klasy wymaganymi plikami JAR. Na przykład ten wyjątek mógł występować podczas wykonywania kodu JDBC w celu połączenia się z bazą danych, tj. MySQL, ale ścieżka klasy nie ma dla niego pliku JAR.
Błąd NoClassDefFoundError występuje, gdy JVM próbuje załadować określoną klasę, która jest częścią wykonania kodu (w ramach normalnego wywołania metody lub w ramach tworzenia instancji przy użyciu nowego słowa kluczowego), a klasa ta nie jest obecna w ścieżce klasy, ale była obecny w czasie kompilacji, ponieważ aby uruchomić program, musisz go skompilować, a jeśli próbujesz użyć klasy, która nie jest obecna, kompilator zgłosi błąd kompilacji.
Poniżej znajduje się krótki opis
Możesz przeczytać Wszystko o ClassNotFoundException Vs NoClassDefFoundError, aby uzyskać więcej informacji.
źródło
Powtarzam sobie raz po raz, kiedy muszę odświeżyć
Klasa nie znaleziono wyjątku
Hierarchia klas
Podczas debugowania
NoClassDefFoundError
Hierarchia klas
Podczas debugowania
źródło
ClassNotFoundException i NoClassDefFoundError występują, gdy konkretna klasa nie zostanie znaleziona w czasie wykonywania, jednak występują one w różnych scenariuszach.
ClassNotFoundException to wyjątek występujący podczas próby załadowania klasy w czasie wykonywania przy użyciu metod Class.forName () lub loadClass (), a wspomnianych klas nie można znaleźć w ścieżce klasy.
NoClassDefFoundError to błąd występujący, gdy dana klasa jest obecna w czasie kompilacji, ale jej brakowało w czasie wykonywania.
Podczas kompilacji powyższego programu zostaną wygenerowane dwa pliki .class. Jeden to A.class, a drugi to B.class. Jeśli usuniesz plik A.class i uruchomisz plik B.class, Java Runtime System wyrzuci NoClassDefFoundError jak poniżej:
źródło