1. ホーム
  2. ジャワ

java.lang.NoClassDefFoundErrorエラーの解決方法

2022-02-22 20:06:26
<パス

前文

普段のJava開発では、java.lang.NoClassDefFoundErrorのようなエラーによく遭遇しますが、どの特定のクラスが見つからないのか、エラーの原因を探るのに時間がかかります。クラスは明らかにまだそこにある、なぜ見つけることができないのですか?そして、我々は簡単にjava.lang.NoClassDefFoundErrorとjava.lang.ClassNotfoundExceptionこれら2つのエラーを、実際には、これら2つのエラーは完全に異なっている混同することができます。私たちはしばしば、エラーの原因を本当に理解することなく、問題を解決するために他のいくつかの方法を試して時間を費やしています。この記事では、NoClassDefFoundErrorのいくつかの秘密を明らかにするためにNoClassDefFoundErrorエラーを解決する経験を共有することです。 開発者。NoClassDefFoundErrorというエラーがなぜ発生するのか、どのように解決するのかを分析しましょう。

NoClassDefFoundErrorエラーの理由

NoClassDefFoundErrorエラーは、Java仮想マシンがコンパイル時に正しいクラスを見つけるが、実行時には見つからないために発生します。例えば、実行時にクラスのメソッドを呼び出したり、このクラスの静的メンバにアクセスしたいときに、そのクラスが利用できないことがわかり、Java仮想マシンがNoClassDefFoundErrorエラーを投げるのです。ClassNotFoundExceptionとの違いは、このエラーがコンパイル時ではなく、対応するクラスの読み込みに失敗する必要がある実行時にのみ発生する点です。多くのJava開発者は、ここでこの2つのエラーを混同してしまいがちです。

簡単にまとめると、NoClassDefFoundErrorは、コンパイル時に対応するクラスが利用できるが、実行時にJavaのクラスパスパスで対応するクラスが利用できない場合に発生します。NoClassDefFoundErrorが発生した場合、以下のようなエラーログが表示されます。

Exception in thread "main" java.lang.NoClassDefFoundError

このエラーメッセージは、メインスレッドが指定されたクラスを見つけることができなかったことを明確に示しており、そのスレッドはメインスレッドか他のサブスレッドである可能性があることを示しています。メインスレッドでエラーが発生した場合はプログラムがクラッシュするか停止し、子スレッドの場合は子スレッドが停止して他のスレッドは実行を継続します。

NoClassDefFoundErrorとClassNotFoundExceptionの違い

java.lang.ClassNotFoundExceptionとjava.lang.NoClassDefFoundErrorは、どちらもJavaのクラスパスに関連するエラーですが、全く別のものです。NoClassDefFoundErrorは、JVMが動的実行時に、指定したクラス名に基づいてクラスパスから該当するクラスを探してロードしますが、クラスを見つけられないときに、java.ClassDefFoundExceptionが表示されます。 lang.NoClassDefFoundErrorのエラーが発生しますが、ClassNotFoundExceptionの場合はコンパイル時にエラーが発生し、その原因がすべて環境の問題であることがわかっているので、NoClassDefFoundErrorより解決しやすいのです。また、J2EE環境で作業をしていてNoClassDefFoundError例外が発生し、そのエラーに該当するクラスが存在する場合、そのクラスはおそらくクラスローダーから見えていないことを意味します。

NoClassDefFoundErrorエラーの修正方法

前回の記事から、NoClassDefFoundErrorエラーは、実行時にクラスローダーがクラスパスの下に読み込む必要があるクラスを見つけることができないため、該当するクラスをクラスパスに読み込むか、クラスパスで利用できない理由を確認する必要があることが明らかですが、このようなことが起きる理由として考えられるのは以下のとおりです。

  1. 対応するクラスがjavaのクラスパスに存在しない。
  2. jarコマンドでプログラムを実行しても、jarファイルのマニフェストファイルのclasspath属性にクラスが定義されていません
  3. プログラムの起動スクリプトが、本来のクラスパス環境変数を上書きしているのかもしれない
  4. NoClassDefFoundErrorはjava.lang.LinkageErrorのサブクラスなので、プログラムが依存しているネイティブクラスライブラリが使用できないことが原因である可能性があります。
  5. java.lang.ExceptionInitializerError, NoClassDefFoundErrorのようなエラーがないか、ログファイルをチェックします。
  6. 複数の異なるクラスローダーがあるJ2EE環境で作業している場合、NoClassDefFoundErrorにつながる可能性もあります。

ここでは、NoClassDefFoundErrorが発生した場合にどのように解決するか、いくつかのサンプル例を見てみましょう。

NoClassDefFoundErrorの解決例

  • NoClassDefFoundErrorエラーは、jarファイルがない場合、jarファイルがクラスパスに追加されていない場合、jarのファイル名が変更されたためにjava.lang.FoundErrorが発生した場合に発生します。
  • これはクラスがクラスパスにない場合、正確に知ることは難しいですが、プログラム内で System.getproperty("java.classpath") を出力すれば、実際にプログラムが動作しているクラスパスを取得することが可能です
  • プログラムが正しく実行されると思われる実行時に、-classpath引数を明示的に指定する。これを追加した後にプログラムが正しく動作するようになれば、元のプログラムのクラスパスが誰かに上書きされたことになる。
  • NoClassDefFoundErrorは、クラスの静的初期化モジュールのエラーによって引き起こされることもあります。あなたのクラスがいくつかの静的な初期化モジュールの操作を実行するとき、初期化モジュールが例外をスローする場合、そのクラスに依存する他のクラスは、NoClassDefFoundErrorエラーをスローします。あなたがプログラムのログを見れば、いくつかのjava.lang.ExceptionInInitializerErrorエラーログを見つけることができます、ExceptionInInitializerErrorエラーはjava.lang.NoClassDefFoundErrorを引き起こします。次のコード例のように、クラスを初期化できませんでした。
/**
 * Java program to demonstrate how failure of static initialization subsequently cause
 * NoClassDefFoundError in Java.
 * @author Javin Paul
 */java.lang.
public class NoClassDefFoundErrorDueToStaticInitFailure {

    public static void main(String args[]){

        List<User> users = new ArrayList<User>(2);

        for(int i=0; i<2; i++){
            try{
            users.add(new User(String.valueOf(i))); //will throw NoClassDefFoundError
            }catch(Throwable t){
                t.printStackTrace();
            }
        }         
    }
}

class User{
    private static String USER_ID = getUserId();

    public User(String id){
        this.USER_ID = id;
    }
    private static String getUserId() {
        throw new RuntimeException("UserId Not found");
    }     
}

Output
java.lang.ExceptionInInitializerError
    at testing.NoClassDefFoundErrorDueToStaticInitFailure.main(NoClassDefFoundErrorDueToStaticInitFailure.java:23)
Caused by: java.lang.RuntimeException: UserId Not found
    at testing.User.getUserId(NoClassDefFoundErrorDueToStaticInitFailure.java:41)
    at testing.User.<clinit>(NoClassDefFoundErrorDueToStaticInitFailure.java:35)
    ... 1 more
java.lang.NoClassDefFoundError: Could not initialize class testing.
    at testing.NoClassDefFoundErrorDueToStaticInitFailure.main(NoClassDefFoundErrorDueToStaticInitFailure.java:23)


Read more: http://javarevisited.blogspot.com/2011/06/noclassdeffounderror-exception-in.html#ixzz3dqtbvHDy


  • NoClassDefFoundErrorはLinkageErrorのサブクラスであり、LinkageErrorエラーは他のクラスに依存している場合に発生するため、アプリケーションがネイティブクラスライブラリに依存している場合に必要なdllが存在しないと、java.lang.NoClassDefFoundErrorが発生する可能性があります。このエラーは、java.lang.UnsatisfiedLinkError: no dll in java.library.path Exception Java のような例外を投げることもあります。解決策は、依存するライブラリとDLLをjarパッケージと一緒に置くことです。
  • Ant ビルド スクリプトを使用して jar ファイルとマニフェスト ファイルを生成する場合、Ant スクリプトが正しいクラスパス値を取得して manifest.mf ファイルに書き込んでいることを確認すること。
  • linux のようなマルチユーザーOS 上でアプリケーションを実行する場合、jar ファイル、クラスライブラリファイル、設定ファイルなどのアプリケーション関連リソースファイルの権限を、アプリケーションが属するユーザーグループに割り当てる必要があります。複数のユーザーでパッケージを共有すると、権限の問題が発生しやすくなります。例えば、他のユーザーがアクセス権を設定したjarパッケージに対して、あなたのアプリケーションはアクセス権を持っておらず、java.lang.NoClassDefFoundErrorエラーが発生します。
  • XML設定ベースのアプリケーションもNoClassDefFoundErrorのエラーにつながる可能性があります。例えば、Spring、StrutsのようなほとんどのJavaフレームワークは、対応するBeanに関する情報を得るためにXMLコンフィギュレーションを使用します。もし間違った名前を入力すると、プログラムは他の間違ったクラスをロードしてNoClassDefFoundError例外を発生させるかもしれません。Spring MVCフレームワークやApache Strutsフレームワークを使っていると、スレッド "main" java.lang.NoClassDefFoundError という例外が発生することがよくあります。NoClassDefFoundErrorが発生します。
  • 複数のClassLoaderを使用するJ2EE環境では、NoClassDefFoundErrorエラーが発生しやすくなります。J2EE では標準のクラスローダを指定していないため、使用するクラスローダは Tomcat、WebLogic、WebSphere などの異なるコンテナに依存し、War パッケージや EJB-JAR パッケージなど J2EE の異なるコンポーネントをロードすることになります。クラスローダーの詳細については、この記事を参照してください。 クラスローダーの仕組み .

    要約すると、クラスローダーは、委任、可視性、特異性という3つのメカニズムに基づいています。委任とは、クラスをロードするリクエストを親クラス・ローダーに与え、その親クラス・ローダーがクラスを見つけられなかったりロードできなかったりした場合に、再度クラスをロードすることを意味します。可視性の原則とは、子クラス・ローダーは親クラス・ローダーがロードしたすべてのクラスを見ることができ、親クラス・ローダーは子クラス・ローダーがロードしたクラスを見ることができない、というものです。特異性の原則とは、クラスが一度だけロードされることを意味し、親クラス・ローダーによってロードされたクラスを子クラス・ローダーが再びロードしないようにするための委譲されたメカニズムである。ここで、UserクラスがWARファイルとEJB-JARファイルの両方に存在し、ロードされたEJB-JAR ClassLoaderの子ClassLoaderであるWAR ClassLoaderによってロードされたと仮定します。EJB-JAR 内のコードがこの User クラスを参照する場合、EJB-JAR 内のすべてのクラスをロードするクラスローダー EJB-JAR 内のコードがこの User クラスを参照する場合、EJB-JAR クラスローダーのサブローダーである WAR クラスローダーによってすでにクラスがロードされているため、このクラスを見つけることができないのです。

    この結果、User クラスで NoClassDefFoundError 例外が発生し、User クラスが両方の JAR パッケージに存在する場合、2 つのクラスのオブジェクトを比較するために equals メソッドを使用すると、2 つの異なるクラスローダーによってロードされたクラスを比較できないため ClassCastException が発生します ...

  • NoClassDefFoundError: com/sun/tools/javac/Main このエラーは、クラスパス、PATH または JAVA_HOME が正しくインストールおよび設定されていない、または JDK が正しくインストールされていないことを意味します。この問題の解決策は、JDKを再インストールすることです。

  • また、Javaはリンク操作の際にNoClassDefFoundErrorを起こすことがあります。例えば、先のスクリプトでは、コンパイル後にUserのコンパイル済みファイルを削除してからプログラムを実行すると、直接NoClassDefFoundErrorが発生し、エラーメッセージにはUserクラスの名前のみが出力されることになります。
java.lang.NoClassDefFoundError: testing/User
    at testing.NoClassDefFoundErrorDueToStaticInitFailure.main(NoClassDefFoundErrorDueToStaticInitFailure.java:23)

これで、NoClassDefFoundError例外に直面し、それを解決する方法を知ることができました。

参考記事

javaにおけるクラスパスの仕組み

Java J2EEでjava.lang.NoClassDefFoundErrorを解決するための3つの方法

JVMでクラスがロードされ、初期化されるとき

クラスローダーの仕組み