logo

Javaのクラスローダー

Java クラスローダー

Java ClassLoader は抽象クラスです。それはに属します java.lang パッケージ。さまざまなリソースからクラスをロードします。 Java ClassLoader は、実行時にクラスをロードするために使用されます。つまり、JVM は実行時にリンク プロセスを実行します。クラスは必要に応じて JVM にロードされます。ロードされたクラスが別のクラスに依存している場合、そのクラスも同様にロードされます。クラスのロードをリクエストすると、クラスはその親に委任されます。このようにして、実行環境内で一意性が維持されます。 Javaプログラムを実行することが必須です。

エキスパートシステム
Javaのクラスローダー

Java ClassLoader は、次の 3 つの原則に基づいています。 代表団可視性 、 そして 独自性

    委任の原則:クラスロードのリクエストを親クラスローダーに転送します。親がクラスを見つけないかロードしない場合にのみ、クラスをロードします。可視性の原則:これにより、子クラス ローダーは、親 ClassLoader によってロードされたすべてのクラスを参照できるようになります。ただし、親クラス ローダーは、子クラス ローダーによってロードされたクラスを認識できません。一意性の原則:クラスを一度ロードすることができます。それは委任の原則によって達成されます。これにより、子 ClassLoader が、親によってすでにロードされているクラスを再ロードしないことが保証されます。

クラスローダーの種類

Java では、すべての ClassLoader には、クラス ファイルをロードする場所が事前に定義されています。 Java には次の種類の ClassLoader があります。

ブートストラップ クラス ローダー: rt.jar およびその他のコア クラスから標準の JDK クラス ファイルをロードします。これはすべてのクラスローダーの親です。親はありません。 String.class.getClassLoader() を呼び出すと null が返され、それに基づくコードは NullPointerException をスローします。これは、Primordial ClassLoader とも呼ばれます。 jre/lib/rt.jar からクラス ファイルをロードします。たとえば、java.lang パッケージ クラスです。

拡張クラスローダー: クラスのロード要求をその親に委任します。クラスのロードが失敗した場合、クラスは jre/lib/ext ディレクトリまたはその他のディレクトリから java.ext.dirs としてロードされます。これは、JVM の sun.misc.Launcher$ExtClassLoader によって実装されます。

システムクラスローダー: CLASSPATH 環境変数からアプリケーション固有のクラスをロードします。 -cp または classpath コマンド ライン オプションを使用してプログラムを呼び出すときに設定できます。 Extension ClassLoader の子です。 sun.misc.Launcher$AppClassLoader クラスによって実装されます。すべての Java ClassLoader は java.lang.ClassLoader を実装します。

Javaのクラスローダー

Java での ClassLoader の仕組み

JVM がクラスをリクエストすると、クラスの完全に分類された名前を渡して、java.lang.ClassLoader クラスのloadClass() メソッドを呼び出します。 loadClass() メソッドは findLoadedClass() メソッドを呼び出して、クラスがすでにロードされているかどうかを確認します。クラスを複数回ロードしないようにするために必要です。

クラスがすでにロードされている場合は、クラスをロードするリクエストを親 ClassLoader に委任します。 ClassLoader がクラスを見つけられない場合、findClass() メソッドを呼び出してファイル システム内のクラスを検索します。次の図は、ClassLoader が委任を使用して Java でクラスをロードする方法を示しています。

Javaのクラスローダー

アプリケーション固有のクラス Demo.class があるとします。このクラス ファイルのロード要求は Application ClassLoader に転送されます。これは、親の Extension ClassLoader に委譲します。さらに、Bootstrap ClassLoader に委譲します。ブートストラップは rt.jar でそのクラスを検索しますが、そのクラスは存在しないためです。次に、Extension ClassLoader への転送を要求します。Extension ClassLoader はディレクトリ jre/lib/ext を検索し、そこでこのクラスを見つけようとします。クラスがそこで見つかった場合、Extension ClassLoader はそのクラスをロードします。アプリケーション ClassLoader はそのクラスをロードしません。拡張機能 ClassLoader がロードしない場合は、アプリケーション ClaasLoader が Java の CLASSPATH からロードします。

可視性の原則では、子 ClassLoader は親 ClassLoader によってロードされたクラスを参照できると規定されていますが、その逆は当てはまりません。つまり、アプリケーション ClassLoader が Demo.class をロードする場合、そのような場合、Extension ClassLoader を使用して Demo.class を明示的にロードしようとすると、java.lang.ClassNotFoundException がスローされます。

一意性の原則に従って、親によってロードされたクラスは、子 ClassLoader によって再度ロードされるべきではありません。そのため、委任と一意性の原則に違反し、クラスを単独でロードするクラス ローダーを作成することが可能です。

つまり、クラスローダーは次のルールに従います。

  • クラスがすでにロードされているかどうかを確認します。
  • クラスがロードされていない場合は、親クラス ローダーにクラスをロードするように依頼します。
  • 親クラス ローダーがクラスをロードできない場合は、このクラス ローダーでクラスのロードを試みます。

次の例を考えてみましょう。

 public class Demo { public static void main(String args[]) { System.out.println('How are you?'); } } 

次のコマンドを使用して、上記のコードをコンパイルして実行します。

 javac Demo.java java -verbose:class Demo 

-verbose:クラス: JVM によってロードされているクラスに関する情報を表示するために使用されます。クラスローダーを使用してクラスを動的にロードする場合に便利です。次の図は出力を示しています。

Javaのクラスローダー

アプリケーション クラス (デモ) に必要なランタイム クラスが最初にロードされることがわかります。

クラスがロードされるとき

ケースは 2 つだけです。

  • 新しいバイトコードが実行されるとき。
  • バイトコードがクラスへの静的参照を作成する場合。例えば、 システムアウト

静的クラスローディングと動的クラスローディング

クラスは「new」演算子を使用して静的にロードされます。動的クラスローディングでは、実行時に Class.forName() メソッドを使用してクラスローダーの関数を呼び出します。

loadClass() と Class.forName() の違い

loadClass() メソッドはクラスのみをロードしますが、オブジェクトは初期化されません。 Class.forName() メソッドは、オブジェクトをロードした後に初期化します。たとえば、ClassLoader.loadClass() を使用して JDBC ドライバーをロードしている場合、クラス ローダーは JDBC ドライバーをロードできません。

java.lang.Class.forName() メソッドは、指定された文字列名のクラスまたはインターフェイスに結合されたクラス オブジェクトを返します。クラスが見つからない場合は、ClassNotFoundException がスローされます。

この例では、java.lang.String クラスがロードされます。クラス名、パッケージ名、および String クラスの使用可能なすべてのメソッドの名前を出力します。次の例では Class.forName() を使用しています。

クラス: 任意のタイプの Class オブジェクトを表します (? はワイルドカードです)。 Class タイプには、クラスに関するメタ情報が含まれます。たとえば、String.class のタイプは Class です。モデル化されているクラスが不明な場合は、「クラス」を使用します。

getDeclaredMethod(): この Class オブジェクトによって表されるクラスまたはインターフェイスのすべての宣言されたメソッドを反映する Method オブジェクトを含む配列を返します。これには、パブリック メソッド、プロテクト メソッド、デフォルト (パッケージ) アクセス、プライベート メソッドが含まれますが、継承されたメソッドは含まれません。

getName(): この Method オブジェクトによって表されるメソッド名を文字列として返します。

 import java.lang.reflect.Method; public class ClassForNameExample { public static void main(String[] args) { try { Class cls = Class.forName('java.lang.String'); System.out.println('Class Name: ' + cls.getName()); System.out.println('Package Name: ' + cls.getPackage()); Method[] methods = cls.getDeclaredMethods(); System.out.println('-----Methods of String class -------------'); for (Method method : methods) { System.out.println(method.getName()); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } } 

出力

 Class Name: java.lang.String Package Name: package java.lang -----Methods of String class ------------- value coder equals length toString hashCode getChars ------ ------ ------ intern isLatin1 checkOffset checkBoundsOffCount checkBoundsBeginEnd access0 access0