HOWTO · Java

Java.Lang.NoClassDefFoundError: クラス エラーを初期化できませんでしたを修正します。

このチュートリアルでは、java.lang.noclassdeffounderror: could not initialize class エラーについて説明し、考えられる理由を説明し、解決策を示します。

このページの内容

今日は、別の実行時エラーについて学習します: java.lang.noclassdeffounderror: could not initialize class. まず、このエラーが発生した Java プログラムを調べて、考えられる理由について議論し、どのコード行がこのエラーを引き起こしているかを突き止めます。

最後に、このエラーを解消するための解決策についても学びます。

Java.Lang.NoClassDefFoundError: クラスを初期化できませんでした エラーが発生した Java プログラム

コード例:

public class PropHolder {
  public static Properties prop;

  static {
    // write code to load the properties from a file
  }
}

コード例:

import java.util.Properties;

public class Main {
  public static void main(String[] args) {
    // set your properties here
    // save the properties in a file
    //  Referencing the PropHolder.prop:
    Properties prop = PropHolder.prop;
    // print the values of all properties
  }
}

ここでは、PropHolder と Main という名前の 2つの .java クラスがあります。 PropHolder クラスは指定されたファイルからプロパティをロードし、Main クラスはプロパティを設定してファイルに保存します。

また、PropHolder クラスの prop 変数を参照して、すべてのプロパティの値を出力します。

この Java コードをローカル マシンで実行すると正常に動作しますが、スクリプトを使用して Linux サーバーに展開すると動作しません。 なぜそうなのですか? 理由を考えてみましょう。

Java.Lang.NoClassDefFoundError: クラスを初期化できませんでした エラーの考えられる原因

まず、java.lang.NoClassDefFoundError を取得することは、クラスが欠落していることを意味するだけではないことを覚えておいてください。 その場合、java.lang.ClassNotFoundException が発生します。

また、バイトコード (.class) が欠落しているという意味でもありません (その場合、この java.lang.NoClassDefFoundError: classname のようなエラーが発生します)。

そのため、サーバーによる java.lang.noclassdeffounderror: could not initialize class エラーは、クラス ファイルが見つからないことを意味します。 これは、以下にリストされているさまざまな理由によって引き起こされる可能性があります。

  1. 問題は static ブロック (static 初期化子とも呼ばれます) にある可能性があります。 キャッチされていない例外とともに表示され、クラスをロードしようとしている実際の ClassLoader まで発生および伝搬されます。

  2. 例外が static ブロックによるものでない場合は、PropHolder.prop という名前の static 変数の作成中に発生した可能性があります。

  3. 指定された Java CLASSPATH で Class が使用できない可能性があります。

  4. MANIFEST ファイルの ClassPath 属性で Class が定義されていないときに、Class コマンドを使用して Java プログラムを実行した可能性があります。

  5. このエラーは、CLASSPATH 環境変数をオーバーライドする起動スクリプトが原因である可能性があります。

  6. 別の理由として、依存関係の欠落が考えられます。 たとえば、NoClassDefFoundError が java.lang.LinkageError の子クラスであるため、ネイティブ ライブラリが利用できない場合があります。

  7. log ファイルで java.lang.ExceptionInInitializerError を探すこともできます。これは、static 初期化の失敗が原因で NoClassDefFoundError が発生している可能性があるためです。

  8. J2EE 環境で作業している場合、別の ClassLoaders での Class の可視性により、java.lang.NoClassDefFoundError エラーが発生する可能性があります。

  9. 場合によっては、JRE/JDK のバージョン エラーが原因で発生することがあります。

  10. たとえば、OpenJDK バージョン 8.x.x を使用して、マシンで何かをコンパイルしたときにも発生する可能性があります。 プッシュ/コミットしますが、他の誰かがその JAVA_HOME を 11.x JDK バージョンに設定しました。

    ここでは、ClassNotFoundError、NoClassDefFoundError などを取得できます。そのため、プログラムがコンパイルされた JDK を確認することをお勧めします。

Java.Lang.NoClassDefFoundError: Could Not Initialize Class エラーを根絶するためのソリューション

私たちの場合、ClassLoader は、クラスを読み込もうとしているときに、クラス定義を読み込んでいるときにエラーに遭遇しました。 したがって、静的イニシャライザ内に try-catch ブロックを配置すると、問題が解決します。

そこでいくつかのファイルを読み取る場合、ローカル環境とは異なることを覚えておいてください。

コード例:

// import libraries
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

// PropHolder Class
public class PropHolder {
  // static variable of type Properties
  public static Properties prop;

  // static block, which loads the properties
  // from the specified file
  static {
    try {
      InputStream input = new FileInputStream("properties");
      prop = new Properties();
      prop.load(input);

    } catch (FileNotFoundException ex) {
      Logger.getLogger(PropHolder.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
      Logger.getLogger(PropHolder.class.getName()).log(Level.SEVERE, null, ex);
    }
  } // end static block
} // end PropHolder class

上記のクラスでは、static ブロックで使用する Properties 型の prop という名前の静的変数を作成しました。 static ブロック内で、ファイル システム内の指定されたファイルから入力バイトを取得する FileInputStream のオブジェクトを作成しました。

次に、指定されたファイルからプロパティをロードするために使用される Properties クラスのコンストラクターを呼び出して、prop 変数を初期化しました。 この static ブロックは、アプリケーションを実行した後にのみ実行されることを覚えておいてください。

コード例:

// import libraries

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

// Main Class
public class Main {
  // main()
  public static void main(String[] args) {
    /*
    instantiate the Properties class, set various
    properties and store them in a given file
     */
    Properties prop = new Properties();
    prop.setProperty("db.url", "localhost");
    prop.setProperty("db.user", "user");
    prop.setProperty("db.password", "password");
    try {
      OutputStream output = new FileOutputStream("properties");
      prop.store(output, null);
    } catch (FileNotFoundException ex) {
      Logger.getLogger(PropHolder.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
      Logger.getLogger(PropHolder.class.getName()).log(Level.SEVERE, null, ex);
    }

    /*
    reference the `PropHolder.prop` to access the values of
    the properties that we set previously
     */
    Properties obj = PropHolder.prop;
    System.out.println(obj.getProperty("db.url"));
    System.out.println(obj.getProperty("db.user"));
    System.out.println(obj.getProperty("db.password"));
  } // end main()
} // end Main

Main クラスでは、Properties クラスをインスタンス化して、さまざまなプロパティの値を設定し、指定したファイルに保存します。 次に、PropHolder.prop を参照して、db.url、db.user、および db.password プロパティの値にアクセスし、次のようにプログラム出力コンソールに出力します。

出力:

localhost
user
password