banner
jzman

jzman

Coding、思考、自觉。
github

Javaシリーズのリフレクション

最近の知識は比較的断片的で、文書に整理するのには適していません。以前の反射に関する学習ノートを一篇、主な内容は以下の通りです。

  1. 反射メカニズム
  2. 反射によるクラスの情報取得
  3. 反射によるクラスの情報操作
  4. 反射によるジェネリックの取得
  5. 反射によるアノテーション情報の取得

反射メカニズム#

Java の反射メカニズムは、実行状態において任意のクラスのすべての属性とメソッドを知ることができることを指します。反射は、コードが実行される際にクラスの情報を動的に取得することができるメカニズムであり、コンパイル時には取得できないクラスの情報を反射を通じて取得できます。任意のクラスがクラスローダー(ClassLoader)によって初めてロードされると、自動的にそのクラスに対応する Class オブジェクトが生成されます。この Class オブジェクトは、対応するクラスのすべての情報を保存します。このように、任意のクラスがクラスローダーによってロードされた後に、Class オブジェクトの情報を動的に取得し、Class オブジェクトの属性やメソッドを動的に操作する機能を Java の反射メカニズムと呼びます。

Java の反射メカニズムの鍵は、特定の任意のクラスの Class オブジェクトを取得することです。以下の内容は、この Class オブジェクトを通じてクラスに関連する情報を取得し、動的に操作する方法です。後の文脈で反射を使用するために、ここで User クラスを作成します。具体的には以下の通りです:

反射によるクラスの情報取得#

ここでは、クラスの基本情報、例えばクラスのコンストラクタ、属性、メソッドなどを取得する方法をまとめます。特定のクラスに対応する Class オブジェクトの getter メソッドを通じて、クラスの名前、コンストラクタ、属性、メソッドなどを取得できます。以下に、特定のクラスのコンストラクタを取得する方法の例を示します:

  • clazz.getConstructors (): 特定のクラス内の public 修飾子を持つすべてのコンストラクタを取得します。getFields ()、getMethods () には、親クラスから継承された public 修飾の属性やメソッドも含まれます。
  • clazz.getDeclaredConstructors (): 特定のクラス内のすべての宣言されたコンストラクタを取得します。本クラスに限定されます。

また、特定のコンストラクタ、属性、メソッドなどを取得することもできます。以下のコードは、主に定義された(Declared)コンストラクタ、属性、メソッドを取得する例です。参考にしてください:

反射を通じて特定のクラスの関連情報を取得する方法は上記の通りです。上記コードの実行結果は以下の通りです:

反射によるクラスの情報操作#

Java の反射メカニズムを使用することで、特定のクラスのコンストラクタ、属性、メソッドを取得し、そのクラスに関連する操作を行うことができます。以下は、Java の反射メカニズムを使用してそのクラスのオブジェクトを構築し、そのクラスオブジェクトの属性を操作し、そのクラスオブジェクトのメソッドを呼び出す方法の具体例です:

上記コードの実行結果は以下の通りです:

実際の開発では、特定のコンポーネントで必要な属性が私有である場合が必ずあります。この場合、Java の反射メカニズムを使用することができます。

反射によるジェネリック操作#

Java はジェネリックの消去メカニズムを採用しており、Java のジェネリックはコンパイラ javac の使用のためだけに存在します。これにより、データの安全性を確保し、強制的な型変換の手間を省くことができます。コンパイルが完了すると、すべてのジェネリックに関連する型はすべて消去されます。これらの型を反射で操作できるようにするために、GenericArrayType、ParameterizedType、TypeVariable、WildcardType の 4 種類の型が追加され、Class クラスに帰属できないが原始型と同名の型を表します。つまり、通常は対応する Class オブジェクトを取得できる Type は Class オブジェクトであり、基本データ型です。

反射によるジェネリック操作は Java の Type に関係します。Java における Type はすべての型の共通インターフェースを表し、これらの型には原始型、パラメータ化型、配列型、型変数、基本型が含まれます。宣言は以下の通りです:

Type には 4 つの直接のサブインターフェースがあり、具体的な意味は以下の通りです:

以下に GenericArrayType と ParameterizedType の例を示し、反射を使用してジェネリック型を操作する方法を具体的に示します:

上記コードのメソッド refectGenericType の実行結果は以下の通りです:

コードを参照して対応する出力結果を確認できます。

反射によるアノテーション情報の取得#

反射を通じてアノテーション情報を取得することもできます。アノテーションに不慣れな場合は、以前に共有した「Java シリーズのアノテーション」を参照してください。ここでは、データベースのテーブルフィールドと Java オブジェクトの属性がどのようにアノテーション情報を通じて対応しているかを簡単に模倣します。なぜデータベースフレームワークを使用する際に、テーブルアノテーションやフィールドアノテーションを通じてテーブルを作成できるのか、ここでは反射を使用してアノテーション情報を取得し、SQL を生成し、対応するテーブルを生成することに関係しています。

テーブルアノテーションとフィールドアノテーションの 2 つのアノテーションを作成し、以下のように参照します:

次に、クラスを作成し、そのアノテーションを使用します。以下のように参照します:

最後に、アノテーション情報を取得します。以下のように参照します:

上記コードの実行結果は以下の通りです:

明らかに、反射を通じて対応するアノテーション情報が取得されました。これらのアノテーション情報は、クラスに対応するデータベーステーブルのいくつかの重要な情報を示しており、これにより対応する SQL 文を生成できます。これにより、データベーステーブルフィールドと Java オブジェクト属性のマッピング関係を理解することが容易になります。

反射を使用して私有属性や私有メソッドを取得するには、setAccessible を true に設定する必要があります。これにより、Java のセキュリティチェックを回避し、私有の属性やメソッドを取得できます。また、setAccessible を true に設定することで、反射の実行速度をある程度向上させることができます。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。