NoClassDefFoundError
Javaアプリケーションを実行するとが表示されます。通常、これの原因は何ですか?
30 に答える
これは、コンパイル時と実行時のクラスパスの不一致が原因である可能性がありますが、必ずしもそうではありません。
この場合、2 つまたは 3 つの異なる例外を頭に入れておくことが重要です。
java.lang.ClassNotFoundException
この例外は、クラスパスでクラスが見つからなかったことを示します。これは、クラス定義をロードしようとしていて、そのクラスがクラスパスに存在しなかったことを示しています。java.lang.NoClassDefFoundError
この例外は、JVM が内部クラス定義データ構造でクラスの定義を探したが、見つからなかったことを示します。これは、クラスパスからロードできなかったということとは異なります。通常、これは、以前にクラスパスからクラスをロードしようとしたが、何らかの理由で失敗したことを示しています。今度はクラスを再度使用しようとしています (前回失敗したため、ロードする必要があります)。以前にロードに失敗したため、ロードしようとさえしません(そして、再び失敗する可能性が合理的に疑われます)。以前の失敗は、ClassNotFoundException または ExceptionInInitializerError (静的初期化ブロックでの失敗を示す)、またはその他のさまざまな問題である可能性があります。要点は、 NoClassDefFoundError は必ずしもクラスパスの問題ではないということです。
これは、コードが依存するクラス ファイルがあり、コンパイル時には存在するが実行時には見つからない場合に発生します。ビルド時と実行時のクラスパスの違いを探します。
説明するコードは次のとおりjava.lang.NoClassDefFoundError
です。詳細な説明については、 Jared の回答を参照してください。
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;
}
実行時に互換性のないバージョンのクラスを使用してコードをコンパイルすると、NoClassDefFound エラーが発生することがあります。私が思い出す特定のインスタンスは、Apache 軸ライブラリを使用したものです。実行時クラスパスには実際には 2 つのバージョンがあり、古いバージョンと互換性のないバージョンが選択され、正しいバージョンではなく、NoClassDefFound エラーが発生しました。これは、これに似たコマンドを使用していたコマンド ライン アプリでした。
set classpath=%classpath%;axis.jar
次を使用して、適切なバージョンを取得することができました。
set classpath=axis.jar;%classpath%;
これは私がこれまでに見つけた最良の解決策です。
org.mypackage
クラスを含むというパッケージがあるとします。
- HelloWorld (メインクラス)
- サポートクラス
- UtilClass
このパッケージを定義するファイルは、ディレクトリD:\myprogram
(Windows の場合) または/home/user/myprogram
(Linux の場合) の下に物理的に保存されます。
Java を呼び出すときは、実行するアプリケーションの名前を指定します: org.mypackage.HelloWorld
. ただし、パッケージを定義するファイルとディレクトリを探す場所を Java に伝える必要もあります。したがって、プログラムを起動するには、次のコマンドを使用する必要があります。
ランタイム クラス ローダーによってロードされたクラスが、Java ルートローダーによって既にロードされているクラスにアクセスできない場合、NoClassFoundError が発生します。異なるクラス ローダーは異なるセキュリティ ドメインにあるため (java によると)、jvm は、ルートローダーによって既にロードされているクラスをランタイム ローダーのアドレス空間で解決することを許可しません。
「java -javaagent:tracer.jar [YOUR Java ARGS]」でプログラムを実行します
ロードされたクラスと、クラスをロードしたローダー env を示す出力が生成されます。クラスを解決できない理由を追跡することは非常に役立ちます。
// 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;
}
});
}
}
以下のテクニックは何度も私を助けました:
System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());
ここで、TheNoDefFoundClass は、プログラムで使用される同じライブラリの古いバージョンを優先するために「失われる」可能性があるクラスです。これは、クライアント ソフトウェアが、独自のクラスローダーと最も人気のあるライブラリの古いバージョンを備えた支配的なコンテナーに展開されている場合に最も頻繁に発生します。
生成されたコード (EMF など) がある場合、すべてのスタック領域を消費する静的初期化子が多すぎる可能性があります。
スタック オーバーフローの質問 Java スタック サイズを増やす方法を参照してください。.
私も同じ問題を抱えていて、何時間も在庫がありました。
解決策を見つけました。私の場合、そのために定義された静的メソッドがありました。JVM は、そのクラスの別のオブジェクトを作成できません。
例えば、
private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http");
module:app
これがとで一致することを確認してくださいmodule:lib
:
android {
compileSdkVersion 23
buildToolsVersion '22.0.1'
packagingOptions {
}
defaultConfig {
minSdkVersion 17
targetSdkVersion 23
versionCode 11
versionName "2.1"
}