反射
クラスクラス
Javaプログラムの実行中、JVMはクラスごとに1つ(1つのみ)のClass
インスタンスを維持します。これは、クラスの情報を記述するために使用されます。
インスタンスを取得
各クラスは、このメソッドを最上位クラスから継承してClass
、そのクラスの一意のインスタンスを返します。
Class getClass();
またはClass
、静的メソッドを使用して、文字列を介してClass
インスタンスを取得します。
static Class forName(String className);
最後の方法は、次のようなclass
キーワードを使用する方法です。
Integer.class;
int.class;
// 基本类型也有 Class 实例
さらに、Class
このクラスのパラメーターなしの構造を呼び出して新しいインスタンスを取得するためのメソッドがあります。
Object newlnstance();
フィールド、メソッド、およびコンストラクタークラス
彼らの例を得る
これらのクラスは、フィールド、メソッド、およびコンストラクターを記述するために使用されます。
Class
のメソッドを介して、対応する配列を返します。
Field[] getFields();
// 返回该类及超类的公有域
Filed[] getDeclaredFie1ds();
// 返回该类的全部域
Method[] getMethods();
// 返回该类及超类的公有方法
Method[] getDeclareMethods();
// 返回该类及接口的全部方法
Constructor[] getConstructors();
// 返回全部公有构造器
Constructor[] getDeclaredConstructors();
// 返回所有构造器
または、文字列の説明で特定のインスタンスを取得します。
Field[] getField(String name);
Filed[] getDeclaredFie1d(String name);
// 通过域名获取 Field 实例
Method[] getMethod(String name, Class<?>... parameterTypes);
Method[] getDeclareMethod(String name, Class<?>... parameterTypes);
// 通过方法名及参数列表的 Class 实例获取 Method 实例
Constructor[] getConstructor(Class<?>... parameterTypes);
Constructor[] getDeclaredConstructor(Class<?>... parameterTypes);
// 通过参数列表的 Class 实例获取 Constructor 实例
名前
Field、Method、ConstructorクラスにはすべてgetName
、名前を取得するためのメソッドがあります。
String getName();
修飾子
getModifiers
モディファイアを取得する方法もあります。
int getModifiers();
返されるintには、すべての修飾子が使用されているかどうかのステータスが含まれています。これModifier
は、クラスの静的メソッドで解決する必要があります。
static String toString(int modifiers);
static boolean isAbstract(int modifiers);
static boolean isFinal (int modifiers);
static boolean islnterface(int modifiers);
static boolean isNative(int modifiers);
static boolean isPrivate(int modifiers);
static boolean isProtected(int modifiers);
static boolean isPubl(int modifiers);
static boolean isStat(int modifiers);
static boolean isStrict(int modifiers);
static boolean isSynchronized(int modifiers);
static boolean isVolatile(int modifiers);
フィールドの種類
特に、Fieldには、getType
fieldのClass
インスタンスを取得するメソッドがあります。
Class getType();
パラメータリストと例外
コンストラクタークラスとメソッドクラスにはgetParameterTypes
、getExceptionTypes
パラメーターリストのタイプとスローされた例外のタイプを取得するためのメソッドがあります。
Class[] getParameterTypes();
Class[] getExceptionTypes();
戻り値のタイプ
メソッドにはgetReturnType
、戻り値の型を取得するためのクラスがあります。
Class getReturnType();
ランタイム操作
Javaの機能は、コンパイラー機能またはインタープリター機能である可能性があることを私たちは知っています。
例えば、方法列挙クラスは、すべての列挙インスタンスの配列を返しますが、少数の人々は、この配列が存在する、またはひどい何の魔法、それがどこにあるかを考えます。ただし、これは実際にはコンパイラの動作です。enum
values
振り返りで検証します。
列挙クラスの場合:
enum State {
Success, Fail;
}
このクラスのフィールド配列を取得し、それらの名前を出力します。
Arrays.asList(State.class.getDeclaredFields())
.forEach(item -> System.out.println(item.getName()));
出力:
成功
不合格
$ VALUES
奇妙なシンボルが現れました$VALUES
。これは実際values
にはメソッドによって返される配列です。
他の方法では操作できなかったドメインを操作するためのいくつかのひどい方法を次に示します。
ランタイム操作ドメイン
フィールドメソッド:
Object get(Object obj);
// 传入一个实例,返回该实例的域值
void set(Object obj ,Object newValue);
// 修改某个实例下该域的值
チェックする前に$VALUES
、まだ議論すべきセキュリティメカニズムがあります。
$VALUES
プライベートドメインの場合、クラスアクセスチェックをバイパスしませんか?これまでのところ、ここに表示されているときにドメインの値を取得しようとすると、IllegalAccessException
例外がスローされます。
FieldsetAccessible
メソッドを使用して、アクセス可能なフラグを設定できます。
void setAccessible(boolean flag);
// 为反射对象设置可访问标志,flag 为 true 表明屏蔽 Java 语言的访问检查,使得对象的私有属性也可以被 get 和 set
boolean isAccessible();
// 返回反射对象的可访问标志的值
static void setAccessible(AccessibleObject[] array, boolean flag);
// 批量为反射对象设置可访问标志
リフレクションオブジェクトは、Field、Method、Constructorなどのクラスを参照します。
これで、クラスアクセスチェックを実際にバイパスしました。
$VALUES
これは確かにプライベートドメインであり、前述のModifier
クラスで確認できます。System.out.println(Modifier.isPrivate(State.class.getDeclaredField("$VALUES").getModifiers()));
出力:
true
テスト:
これらの2つのメソッドは例外を処理する必要があることに注意してください。
try {
Field values = State.class.getDeclaredField("$VALUES");
values.setAccessible(true);
Arrays.asList((State[]) values.get(State.Success))
.forEach(System.out::println);
} catch (Exception e) {
e.printStackTrace();
}
出力:
成功
不合格
実行時にオブジェクトを構築する
Javaは安全でない型変換(ダウンキャスト)を禁止しているため、ユニバーサルメソッドを実装することは困難です。
ユニバーサルメソッドは、あらゆるタイプに使用できることを意味します。たとえば、メソッドがオブジェクトパラメータを受け入れる場合、このタイプの新しいインスタンスを作成する必要がある場合はどうすればよいですか?
Constructor
静的メソッドを使用するnewInstance
:
これはClass
、null以外のパラメーターコンストラクターを呼び出すnewInstance
ことConstructor
ができるものとは異なります。
Object newlnstance(Object[] args);
次に、実装Arrays.copyOf
方法の例を見てみましょう。
配列をインスタンス化するには、Arrayの静的メソッドを使用できます。
static Object newInstance(Class<?> componentType, int length);
// 通过数据类型和长度构造一个数组
最初のパラメーターはClass
、次のgetComponentType
方法で取得されます。
Class getComponentType();
実装は次のとおりです。
ポリモーフィズムを介しClass
て要素タイプのインスタンスを取得し、を呼び出してArray.newInstance
配列をインスタンス化します。
public static Object[] expend(Object[] arr, int length) {
Object[] newArr = (Object[]) Array.newInstance(arr.getClass().getComponentType(), length);
for (int i = 0; i < Math.min(arr.length, newArr.length); i++) {
newArr[i] = arr[i];
}
return newArr;
}
メソッドポインタ
メソッドポインタは、Methodクラスのインスタンスを参照します。特定またはすべてを取得するかどうかにかかわらず、メソッドインスタンスを取得するいくつかの方法は、このセクションの冒頭に詳細にリストされています。
メソッド各インスタンスには、invoke
メソッドオブジェクトメソッド呼び出しで説明されているメソッドがあります。
Object invoke(Object obj, Object... args)
最初のパラメーターは、メソッドの暗黙的なパラメーターですthis
。つまり、メソッドを呼び出すオブジェクトを指す、またはオブジェクトとして理解されるオブジェクトです。次はメソッドのパラメータリストです。
静的型の場合、最初のパラメーターを渡すnull
か、任意の値を渡すことができます(結局、静的メソッドで使用する必要はありませんthis
)。
このinvoke
メソッドは、フィールドのget
sumset
メソッドに似ています。アクセスが制限されているメソッドの場合、対応するメソッドインスタンスを呼び出してsetAccessible
、アクセスチェックをバイパスする必要もあります。
必要がない場合は、関数ポインタを使用してメソッドを呼び出さないでください。これは面倒でエラーが発生しやすくなります。
コールバック関数が必要な場合は、インターフェースまたはラムダを使用する必要があります。