私が初めて Java を学習し始めたとき、リフレクションとは何かを理解するのが非常に困難でした。
非常に古典的な本であっても、人々を混乱させるような方法で物事を説明している本もあります。
また、今後フレームワークを学習する際にはリフレクションの仕組みを多用する必要があるとネット上で言われていて、常に不安を感じます。
たまたま反射について説明した章やビデオをいくつか見たのですが、少しは理解できるようになったと思います。
ここで、読み取りと書き込みを同時に頑張って行い、主な内容と操作をここに記録することにしました。
私のような愚かな人間にとって、おそらく最良の学習方法は繰り返し行うことだと思います。
分からない事が出てきたら立ち止まって勉強し直すのはとても時間の無駄ですが、自分にとっても良い影響を与えてくれます。
私の理解では、いわゆるリフレクションとは、すでにインスタンス化されたオブジェクトに基づいてクラスの完全な情報を復元することです。
少なくとも私にとって、それがもたらす利点は、オブジェクト指向を下から上まで理解できることだと思います。
x_x ここで私はあの分厚い頭がまた嫌いです、彼らは私の脳細胞をすべて殺しました。
クラスクラスリフレクションを完了したい場合は、Class クラスを理解する必要があります。
例 1: オブジェクトを通じてパッケージ名とクラス名を取得するクラステスト{
}
パブリック クラス デモ {
public static void main(String[] args) {
テスト t = 新しい Test();
System.out.println(t.getClass());
System.out.println(t.getClass().getName());
}
}
コンパイル結果は次のとおりです。パッケージがどのようにコンパイルされるかに注意してください。
ここでの getClass() メソッドは、デフォルトで Object クラスから継承されます。
Java では、Object クラスはすべてのクラスの親クラスであり、同様に、すべてのクラスのインスタンス化されたオブジェクトも Class クラスのインスタンスです。
したがって、これには上方変換と下方変換の概念が含まれます。
下方キャストの不安により、ジェネリックもここに続きます。
(しかし、私が言いたいのは、ここでの一般的な設計が非常にまぶしいということです! くそー、Java 全体の構文設計もまたまばゆいばかりで、超うんざりです!!!)
例 2: Class クラスのインスタンス化Class クラスにはコンストラクターがないため、Class クラスをインスタンス化する方法は少し特殊です。次の 3 つの方法があります。
Object.getClass()}
パブリック クラス デモ {
public static void main(String[] args) {
//方法 1:
テスト t = 新しい Test();
クラス<? テストを拡張> c1 = t.getClass();
System.out.println(c1);
//方法 2:
//特異性を避けるため、ここでは Test クラスを使用せず、Java ライブラリの String クラスを使用します。
Class<String> c2 = String.class;
System.out.println(c2);
//方法 3:
//forName() メソッドは例外をスローします
クラス<?> c3 = null;
試す {
c3 = Class.forName("テスト");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(c3);
}
}
Class クラスには newInstance() というメソッドがあり、これを使用して Class クラス オブジェクトの新しいインスタンスを作成できます。
どう言えばいいでしょうか? Class オブジェクトに含まれるコンテンツは、反映されたクラスです。そのクラスの新しいインスタンス (新しいオブジェクト) を構築する必要があります。
例 3: Class クラスのパラメータを使用しないオブジェクトの構築 //文字列への参照を生成します
文字列 s = null;
試す {
//構築されたオブジェクトを String クラスにダウンキャストします
//newInstance() メソッドは例外をスローします
s = (文字列) c.newInstance();
catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
System.out.println("文字列の長さ: " + s.length());
}
}
これは、通常モードと同様に、パラメータのない形式で新しいオブジェクトを構築します。
引数なしのコンストラクターを使用して新しいオブジェクトを構築することは、次の場合と同じです。
クラスにはパラメーターなしのコンストラクターに加えて、パラメーター化されたコンストラクターもあることはわかっています。
では、リフレクションでパラメータの形式でオブジェクトを構築するにはどうすればよいでしょうか?続きを読む
例 4: Class クラスのパラメータ化された構築オブジェクトパブリック クラス デモ {
//以下のメソッドはスローする例外が多すぎます。コードをコンパクトにするため、ここでは仮想マシンに直接スローされます。
public static void main(String[] args) throws Exception {
クラス<?> c = null;
試す {
c = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
char[] ch = {'h','e','l','l','o'};
文字列 s = null;
//Class オブジェクトのパラメータ化されたコンストラクタを取得します。括弧内のパラメータは type.class のように記述されます。
Constructor<?> con = c.getConstructor(char[].class);
//この構築メソッドを使用して新しい文字列オブジェクトを構築します。パラメータは char 配列です
s = (文字列) con.newInstance(ch);
System.out.println("構築された文字列: " + s);
}
}
String クラスはより頻繁に使用され、理解しやすいため、引き続き例として String クラスを使用します。
ここで注意する必要があるのは、コンストラクターは getConstructor() メソッドを使用して取得する必要があることです。
パラメータの型は、original type.class となります。
もう 1 つのポイントは、パラメーターがあるかどうかに関係なく、ここで使用される構築メソッドは元のクラスに存在する必要があるということです。
では、元のクラスのコンストラクターメソッド、通常のメソッド、継承された親クラスなどの詳細情報を知るにはどうすればよいでしょうか。続きを読む
クラスの構造を取得するリフレクションを通じてクラスの構造を取得するには、新しいパッケージ java.lang.reflect をインポートする必要があります。
例 5: クラスのコンストラクターを取得するパブリック クラス デモ {
//以下のメソッドはスローする例外が多すぎます。コードをコンパクトにするため、ここでは仮想マシンに直接スローされます。
public static void main(String[] args) throws Exception {
クラス<?> c = null;
試す {
c = Class.forName("java.lang.Boolean");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//ここでの getConstructors() メソッドはコンストラクター配列を返します
コンストラクター<?>[] cons = c.getConstructors();
// 印刷メソッドは自分で作成できますが、便宜上、Arrays.toString() を使用します。
System.out.println(Arrays.toString(cons));
}
}
パブリック クラス デモ {
public static void main(String[] args) throws Exception {
クラス<?> c = null;
試す {
c = Class.forName("java.lang.Boolean");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Class<?>[] in = c.getInterfaces();
System.out.println(Arrays.toString(in));
}
}
パブリック クラス デモ {
public static void main(String[] args) throws Exception {
クラス<?> c = null;
試す {
c = Class.forName("java.lang.Boolean");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
メソッド[] m = c.getMethods();
//さて、今回は慈悲深く、印刷用のリストを書きます。
for (int i = 0; i < m.length; i++) {
System.out.println(m[i]);
}
}
}
クラス人 {
プライベート文字列名。
プライベートの年齢。
}
パブリック クラス デモ {
public static void main(String[] args) throws Exception {
クラス<?> c = null;
試す {
c = Class.forName("人");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
フィールド[] f = c.getDeclaredFields();
for (int i = 0; i < f.length; i++) {
System.out.println(f[i]);
}
}
}
getDeclaredFielsd() メソッドはすべてのプロパティを取得できますが、getFields() はパブリック プロパティのみを取得できます。
例 10: このクラスの属性の値を取得するクラス人 {
パブリック文字列名。
プライベートの年齢。
public Person(文字列名、整数の年齢) {
this.name = 名前;
this.age = 年齢;
}
}
パブリック クラス デモ {
public static void main(String[] args) throws Exception {
人 p = 新しい人("zhangsan",12);
Class<?> c = p.getClass();
//パブリック属性の値を取得する
フィールド f1 = c.getField("名前");
//get(p) はどのオブジェクト値を取得するかを示します
文字列 str = (文字列) f1.get(p);
System.out.println("名前: " + str);
//プライベート属性の値を取得する
フィールド f2 = c.getDeclaredField("年齢");
//age はプライベート プロパティなので、セキュリティ チェックを true に設定します
f2.setAccessible(true);
int age = (int) f2.get(p);
System.out.println("年齢: " + 年齢);
}
}
率直に言って、私のチタンの目を失明させるような Java の知識は見つかりませんでした。
毎回、ガジェットを実装するために面倒な構文を大量に記述するか、API を必死に呼び出して例外をスローする必要があります。
十分にコンパクトでないコードは煩雑になる
ある言語が好きなら、それを使って何かを作る前に、その言語自体の特徴に感銘を受ける必要があります。
明らかに、Java は私を満足させません。おそらく、私のような多くのプログラマーは Java を使用せざるを得ません。
私の孤独なコーディング心を和らげるために、以下を読んでください。
リフレクションの適用例 11: リフレクションによる属性の変更クラス人 {
プライベート文字列名。
public 人(文字列名) {
this.name = 名前;
}
public String toString() {
"名前: " + this.name; を返します。
}
}
パブリック クラス デモ {
public static void main(String[] args) throws Exception {
人 p = new 人("王二狗");
System.out.println(p);
Class<?> c = p.getClass();
// 変更するプロパティを定義します
フィールド f = c.getDeclaredField("名前");
f.setAccessible(true);
//プロパティを変更し、設定するオブジェクトと値を渡します
f.set(p, "張爾丹");
System.out.println(p);
}
}
クラス人 {
public void print(int i) {
System.out.println("数字を書いています: " + i);
}
public static void Say(String str) {
System.out.println("私はこう言っています: " + str);
}
}
パブリック クラス デモ {
public static void main(String[] args) throws Exception {
人 p = 新しい人();
Class<?> c = p.getClass();
//getMethod() メソッドはメソッド名とパラメータのタイプを渡す必要があります
メソッド m1 = c.getMethod("print", int.class);
//invoke() は呼び出しを意味し、オブジェクトとパラメータを渡す必要があります
m1.invoke(p, 10);
メソッド m2 = c.getMethod("say", String.class);
//ここでの null は、オブジェクト、つまり静的メソッドによって呼び出されないことを意味します
m2.invoke(null, "あなたの妹");
}
}
ここでは、通常のパラメータ化メソッドと静的メソッドのデモンストレーションを示します。
すべてのパラメータが書き出されたので、パラメータのないパラメータはオブジェクトを直接渡すだけです。
例 13: リフレクションによる配列の操作パブリック クラス デモ {
public static void main(String[] args) throws Exception {
int[] arr = {1,2,3,4,5};
Class<?> c = arr.getClass().getComponentType();
System.out.println("配列型: " + c.getName());
int len = Array.getLength(arr);
System.out.println("配列の長さ: " + len);
System.out.print("配列を走査する: ");
for (int i = 0; i < len; i++) {
System.out.print(Array.get(arr, i) + " ");
}
System.out.println();
//配列を変更する
System.out.println("変更前の最初の要素: " + Array.get(arr, 0));
Array.set(arr, 0, 3);
System.out.println("変更された最初の要素: " + Array.get(arr, 0));
}
}
私が読んだ本には、ファクトリーモードでのリフレクションの適用も含まれています。
これを forName() メソッドに置き換えるだけです。特に言うことはありません。
私は Java の初心者です。Java の不快な構文と設計が嫌いです。
これはすべて、Android の基礎を築き、将来の作業に適応するためのものです。