【Core Java】04 Java 反射

反射

クラスクラス

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にはgetTypefieldのClassインスタンスを取得するメソッドがあります

Class getType();

パラメータリストと例外

コンストラクタークラスとメソッドクラスにはgetParameterTypesgetExceptionTypesパラメーターリストのタイプとスローされた例外のタイプを取得するためのメソッドあります。

Class[] getParameterTypes();
Class[] getExceptionTypes();

戻り値のタイプ

メソッドにはgetReturnType、戻り値の型を取得するためのクラスがあります。

Class getReturnType();

ランタイム操作

Javaの機能は、コンパイラー機能またはインタープリター機能である可能性があることを私たちは知っています。

例えば、方法列挙クラスは、すべての列挙インスタンスの配列を返しますが、少数の人々は、この配列が存在する、またはひどい何の魔法、それがどこにあるかを考えます。ただし、これは実際にはコンパイラの動作です。enumvalues

振り返りで検証します。

列挙クラスの場合:

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

これはClassnull以外のパラメーターコンストラクターを呼び出す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メソッドはフィールドのgetsumsetメソッドに似ています。アクセスが制限されているメソッドの場合、対応するメソッドインスタンスを呼び出してsetAccessible、アクセスチェックバイパスする必要もあります。

必要がない場合は、関数ポインタを使用してメソッドを呼び出さないでください。これは面倒でエラーが発生しやすくなります。

コールバック関数が必要な場合は、インターフェースまたはラムダを使用する必要があります。

おすすめ

転載: blog.csdn.net/qq_16181837/article/details/112295192