Java Reflectionを使用して特定のフィールドに値を設定する
16145 ワード
JAva replicationの定義
実行中のJavaプログラムからクラス情報を動的に取得して処理できるJava基本API
また、特定のクラスで定義されたフィールド、メソッド、および作成者情報、およびメソッドで宣言されたパラメータ情報を表示することもできます.
これらのクエリーのフィールド、メソッド、作成者などの情報により、単純値クエリー/設定からメソッド実行までの操作を処理できます.
この文書では、Javaが提供するReplication APIを使用して、クラスで宣言されたフィールドをチェックし、値の変更/クエリーを試みます.
例:ドメインクラスを使用して、次のように一般的な値を格納します.
直接アクセスフィールドを回避するために、フィールドにプライベートアクセス制御者を指定し、getter/setterを作成して値を設定および取得します.
lombokのようなライブラリを使用するとgetter/setterを簡単に作成できますが、例を明確にするために1つずつ作成されています.
package dy.sample.reflection.domain;
public class NumberingItemInfo {
private int item1;
private int item2;
private int item3;
public int getItem1() {
return item1;
}
public void setItem1(int item1) {
this.item1 = item1;
}
public int getItem2() {
return item2;
}
public void setItem2(int item2) {
this.item2 = item2;
}
public int getItem3() {
return item3;
}
public void setItem3(int item3) {
this.item3 = item3;
}
}
クラスで定義されたフィールド情報を取得します。
まずターゲットクラス情報を取得するには、3つの方法があります.
Class targetClass = NumberingItemInfo.class;
Class targetClass = Class.forName("dy.sample.reflection.domain.NumberingItemInfo");
NumberingItemInfo numberingItemInfo = new NumberingItemInfo();
numberingItemInfo.getClass();
これらのインポートされたクラス・オブジェクトには、次の方法を使用してクラスで宣言されたフィールド情報をクエリーできます.クラスで定義されたすべてのフィールド情報を取得し、Fieldタイプの配列に戻ります.この場合、フィールドのアクセス制御者が誰であるかにかかわらず、クエリーが行われます.
クラスで定義されたすべてのフィールド情報を取得し、Fieldタイプの配列に戻ります.この場合、アクセス制御者によっては外部からアクセス可能な場合のみクエリーが行われます.
クラスで定義されたフィールドの指定した名前と同じフィールド情報をFieldタイプのオブジェクトに返します.指定した名前のフィールドが見つからない場合は、アクセス制御者が誰であってもクエリーが可能なNoSuchFieldExceptionが表示されます.
クラスで定義されたフィールドの指定した名前と同じフィールド情報をFieldタイプのオブジェクトに返します.指定した名前のフィールドが見つからない場合は、「NoSuchFieldException」と表示され、アクセス制御者によっては外部からアクセス可能なフィールドしか見つかりません.
Fieldオブジェクトの大まかな内容を簡単に撮りましょう.
NumberingItemInfo numberingItemInfo = new NumberingItemInfo();
Arrays.stream(numberingItemInfo.getClass().getDeclaredFields())
.forEach(field -> System.out.println("field = " + field.toString()));
結果field = private java.lang.String dy.sample.reflection.domain.NumberingItemInfo.item1
field = private java.lang.String dy.sample.reflection.domain.NumberingItemInfo.item2
field = private java.lang.String dy.sample.reflection.domain.NumberingItemInfo.item3
Fieldクラスで再定義されたtoStringメソッドによって指定されたクラス名{アクセス制御者}{タイプ}{パッケージパスを含む}です.フォーマットで出力します.また,Fieldオブジェクトには,フィールドに適した説明情報,制御者(static,finalなど)などの情報が含まれている.getFieldsメソッドを使用すると、何も出力されません.各フィールドのアクセス制御者はプライベートなので.
コードの例
いよいよ返信で価格設定.item 2フィールドに迷ったことを書きます.プライベートフィールドであることを知っているため、getDeclaredFieldメソッドを使用します.
NumberingItemInfo numberingItemInfo = new NumberingItemInfo();
Field targetField = numberingItemInfo.getClass().getField("item2");
targetField.set(numberingItemInfo, "리플렉션으로 수정한 값-item2");
こうして作成して実行すると...このようなエラーが発生する可能性があります.java.lang.IllegalAccessException: Class dy.sample.reflection.service.NumberingService can not access a member of class dy.sample.reflection.domain.NumberingItemInfo with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
at java.lang.reflect.Field.set(Field.java:761)
at dy.sample.reflection.service.NumberingService.main(NumberingService.java:15)
このフィールドはprivateとして指定されているため、アクセスできません.getDeclaredFieldメソッドを使用してprivateフィールドの情報を取得できますが、このように簡単に変更することは防止されます.
しかし、これは完全に不可能ではありません.コードを修正して、次のように実行します.
NumberingItemInfo numberingItemInfo = new NumberingItemInfo();
Field targetField = numberingItemInfo.getClass().getField("item2");
targetField.setAccessible(true);
targetField.set(numberingItemInfo, "리플렉션으로 수정한 값-item2");
前述したように、setアクセスメソッドを使用してフィールドをtrueとして指定して再実行した場合、エラーは発生しません.今回も値段を撮ってみましょう
NumberingItemInfo numberingItemInfo = new NumberingItemInfo();
Field targetField = numberingItemInfo.getClass().getDeclaredField("item2");
targetField.setAccessible(true); // 필드 값에 접근 가능하도록 허용하기
targetField.set(numberingItemInfo, "리플렉션으로 수정한 값-item2"); // 값 세팅하기
System.out.println("Value of item2 : " + targetField.get(numberingItemInfo)); // 값 조회하기
結果Value of item2 : 리플렉션으로 수정한 값-item2
Process finished with exit code 0
クエリー値にプライベートアクセス制限も指定されている場合は、setアクセス性で変更してアクセスを許可する必要があります.また、2行目のFieldオブジェクトを取得するコードには、NumberingItemInfoインスタンスという名前のフィールド情報はありません.NumberingItemInfoのソースクラスで定義されているitem 2というフィールドメタデータ情報を取得しました.したがって、targetFieldオブジェクトにはNumberingItemInfoに格納されている値は含まれません.
に報いる
運用中のサービスでは、最大15個の番号フィールドを処理する必要がある場合があります.
これらのフィールド値を処理する論理にレプリケーションが適用されていない場合、
オブジェクト(または同じ仕様テーブル)を使用する他の機能がある場合は、その機能を実装するコードに同じフィールド数のコードを記述する必要がある場合があります.上記の問題があります.
しかし、これは無条件ではなく、プライベート範囲に指定されたフィールドに直接アクセスし、値を勝手に変更することで、いくつかの大きなルールを破ったようです.
最終的には個人の判断でこれらの機能を使うかどうかを決めますが、私の場合のように、効率の面で大きな違いがある場合は、適切に使うのも悪くありません.
それ以外は
この文書では、Fieldのみをチェックしていますが、クラスで定義されているメソッド、作成者、デモンストレーション者、制御者、インタフェース、サブクラスなどの多くの情報を表示し、必要に応じて多くの操作(たとえば、特定のクラスで定義されているメソッド情報をクエリーする)を実行することもできます.「フィールド名を簡単に動的に指定して値を設定する方法はないか」という好奇心から、返信を知り、関連情報を最大限に簡略化して分析し、学ぶべきことが多く、開発に際して考慮すべきことも多いと感じました.
リファレンスサイト
https://happyitpark.tistory.com/6
https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/package-summary.html
https://docs.oracle.com/javase/tutorial/reflect/
Reference
この問題について(Java Reflectionを使用して特定のフィールドに値を設定する), 我々は、より多くの情報をここで見つけました https://velog.io/@devbydy/자바-리플렉션을-이용하여-특정-필드에-값-세팅하기テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol