677 Stimmen

Warum erhalte ich einen NoClassDefFoundError in Java?

Ich bekomme eine NoClassDefFoundError wenn ich meine Java-Anwendung ausführe. Was ist typischerweise die Ursache dafür?

1 Stimmen

Ich glaube, es kann auch passieren, wenn Sie Ihr Java-Programm nicht mit der richtigen Syntax ausführen. Zum Beispiel müssen Sie Ihre Klasse aus dem Root-Bin-Ordner mit dem vollständigen Paketnamen aufrufen (z. B. my.package.myClass). Ich würde genauer sein, wenn ich könnte, aber ich bin kein großer Java-Kenner. Ich kann mich nur daran erinnern, dass ich das ein paar Mal vermasselt habe.

10voto

Bartek Lipinski Punkte 29098

Ein interessanter Fall, in dem Sie viel sehen könnten NoClassDefFoundErrors ist, wenn Sie:

  1. throw a RuntimeException im static Block Ihrer Klasse Example
  2. Abfangen (oder wenn es einfach keine Rolle spielt, wie es in einem Testfall )
  3. Versuchen Sie, eine Instanz dieser Klasse zu erzeugen 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 geworfen werden, begleitet von ExceptionInInitializerError aus dem statischen Block RuntimeException .


Dies ist besonders wichtig, wenn Sie sehen NoClassDefFoundErrors in Ihrem EINHEITSTESTS .

In gewisser Weise "teilen" Sie die static Ausführung zwischen den Tests zu blockieren, aber die anfängliche ExceptionInInitializerError wird nur in einem Testfall sein. Der erste, der das problematische Example Klasse. Andere Testfälle, die die Example Klasse wird einfach NoClassDefFoundErrors .

4 Stimmen

Das ist ein verdammt nützlicher Ratschlag für das wirkliche Leben. Ich hatte gerade die gleiche Situation mit Klassenattribut-Initialisierern. Man hat nur einmal die Chance, das eigentliche Problem im Protokoll zu sehen. Sobald die Klasse geladen ist (oder es zumindest versucht wird), müssen Sie alles neu starten.

9voto

Ram Patra Punkte 15496

C'est le beste Lösung die ich bis jetzt gefunden habe.

Angenommen, wir haben ein Paket namens org.mypackage die die Klassen enthalten:

  • HelloWorld (Hauptklasse)
  • SupportClass
  • UtilClass

und die Dateien, die dieses Paket definieren, werden physisch unter dem Verzeichnis D:\myprogram (unter Windows) oder /home/user/myprogram (unter Linux).

Die Dateistruktur wird wie folgt aussehen: enter image description here

Wenn wir Java aufrufen, geben wir den Namen der Anwendung an, die ausgeführt werden soll: org.mypackage.HelloWorld . Allerdings müssen wir Java auch mitteilen, wo die Dateien und Verzeichnisse, die unser Paket definieren, zu suchen sind. Um das Programm zu starten, müssen wir also den folgenden Befehl verwenden: enter image description here

6voto

Nikhil Sahu Punkte 2240

Ich benutzte Spring Framework con Maven und löste diesen Fehler in meinem Projekt.

Es gab einen Laufzeitfehler in der Klasse. Ich habe eine Eigenschaft als Ganzzahl gelesen, aber als der Wert aus der Eigenschaftsdatei gelesen wurde, war der Wert doppelt.

Spring hat mir keinen vollständigen Stack-Trace gegeben, in welcher Zeile die Laufzeit fehlgeschlagen ist. Es sagte einfach NoClassDefFoundError . Aber wenn ich sie als native Java-Anwendung ausführe (und sie aus MVC herausnehme), gibt sie ExceptionInInitializerError was die wahre Ursache war und wie ich den Fehler zurückverfolgt habe.

Die Antwort von @xli gab mir Aufschluss darüber, was in meinem Code falsch sein könnte.

2 Stimmen

Das Gleiche passierte mir bei der Programmierung eines Servlets ( NoClassDefFoundError wurde tatsächlich verursacht durch ExceptionInInitalizerError die verursacht wurde durch DateTimeParseException ). Das ist ein bisschen irreführend, nicht wahr? Ich weiß, dass sie wahrscheinlich ihre Gründe hatten, es so zu machen, aber es wäre so schön, wenigstens einen kleinen Hinweis zu haben, dass NoClassDefFoundError auf eine andere Ausnahme zurückzuführen ist, ohne dass diese abgeleitet werden muss. Einfach werfen ExceptionInInitializerError wäre wieder viel klarer. Manchmal ist die Verbindung zwischen den beiden nicht so offensichtlich.

5voto

Aram Paronikyan Punkte 1552

Die nachstehende Technik hat mir schon oft geholfen:

System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());

wobei die TheNoDefFoundClass die Klasse ist, die aufgrund einer Präferenz für eine ältere Version der gleichen Bibliothek, die von Ihrem Programm verwendet wird, "verloren" gehen könnte. Dies geschieht am häufigsten in den Fällen, in denen die Client-Software in einem dominanten Container bereitgestellt wird, der mit seinen eigenen Classloadern und tonnenweise alten Versionen der beliebtesten Bibliotheken ausgestattet ist.

5voto

codeDr Punkte 1397

Ich erhalte NoClassFoundError, wenn vom Runtime Classloader geladene Klassen nicht auf bereits vom Java Rootloader geladene Klassen zugreifen können. Da sich die verschiedenen Klassenlader in unterschiedlichen Sicherheitsdomänen befinden (laut Java), lässt der JVM nicht zu, dass Klassen, die bereits vom Rootloader geladen wurden, im Adressraum des Runtime-Laders aufgelöst werden.

Starten Sie Ihr Programm mit 'java -javaagent:tracer.jar [IHR java ARGS]'.

Es erzeugt eine Ausgabe, die die geladene Klasse und die Loader-Env, die die Klasse geladen hat, anzeigt. Das ist sehr hilfreich, um herauszufinden, warum eine Klasse nicht aufgelöst werden kann.

// 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;
            }
        });
    }
}

1 Stimmen

Der Link ist tot. Versuchen Sie die archivierte Version: web.archive.org/web/20131216000019/https://blogs.oracle.com/

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X