Javaリフレクションを使用するときのgetFields
メソッドとgetDeclaredFields
メソッドの違いについて少し混乱しています。
getDeclaredFields
はクラスのすべてのフィールドにアクセスでき、getFields
はパブリックフィールドのみを返すことを読みました。この場合、なぜgetDeclaredFields
を常に使用しないのですか?
誰かがこれについて詳しく説明して、2つの方法の違いを説明し、いつ/なぜ他の方法を使用したいのですか?
クラス階層全体のすべてのpublic
フィールド。
アクセシビリティに関係なく、現在のクラスのみのすべてのフィールド。現在のクラスが継承する可能性のある基本クラスではありません。
階層のすべてのフィールドを取得するために、次の関数を作成しました。
public static Iterable<Field> getFieldsUpTo(@Nonnull Class<?> startClass,
@Nullable Class<?> exclusiveParent) {
List<Field> currentClassFields = Lists.newArrayList(startClass.getDeclaredFields());
Class<?> parentClass = startClass.getSuperclass();
if (parentClass != null &&
(exclusiveParent == null || !(parentClass.equals(exclusiveParent)))) {
List<Field> parentClassFields =
(List<Field>) getFieldsUpTo(parentClass, exclusiveParent);
currentClassFields.addAll(parentClassFields);
}
return currentClassFields;
}
exclusiveParent
クラスは、Object
からのフィールドの取得を防ぐために提供されています。 null
フィールドが必要な場合は、Object
になります。
明確にするために、Lists.newArrayList
はGuavaから来ています。
参考までに、上記のコードは、GitHubの LibEx プロジェクトの ReflectionUtils で公開されています。
既に述べたように、Class.getDeclaredField(String)
は、呼び出したClass
のフィールドのみを調べます。
Field
階層内のClass
を検索する場合は、次の単純な関数を使用できます。
/**
* Returns the first {@link Field} in the hierarchy for the specified name
*/
public static Field getField(Class<?> clazz, String name) {
Field field = null;
while (clazz != null && field == null) {
try {
field = clazz.getDeclaredField(name);
} catch (Exception e) {
}
clazz = clazz.getSuperclass();
}
return field;
}
これは、たとえばスーパークラスからprivate
フィールドを見つけるのに便利です。また、値を変更する場合は、次のように使用できます。
/**
* Sets {@code value} to the first {@link Field} in the {@code object} hierarchy, for the specified name
*/
public static void setField(Object object, String fieldName, Object value) throws Exception {
Field field = getField(object.getClass(), fieldName);
field.setAccessible(true);
field.set(object, value);
}
public Field[] getFields() throws SecurityException
これによって表されるクラスまたはインターフェースのすべてのアクセス可能なパブリックフィールドを反映するFieldオブジェクトを含む配列を返しますクラスオブジェクト。返される配列内の要素はソートされておらず、特定の順序ではありません。このメソッドは、クラスまたはインターフェイスにアクセス可能なパブリックフィールドがない場合、または配列クラス、プリミティブ型、またはvoidを表す場合、長さ0の配列を返します。
具体的には、このClassオブジェクトがクラスを表す場合、このメソッドはこのクラスとそのすべてのスーパークラスのパブリックフィールドを返します。このClassオブジェクトがインターフェイスを表す場合、このメソッドはこのインターフェイスとそのすべてのスーパーインターフェイスのフィールドを返します。
配列クラスの暗黙の長さフィールドは、このメソッドには反映されません。ユーザーコードは、Arrayクラスのメソッドを使用して配列を操作する必要があります。
public Field[] getDeclaredFields() throws SecurityException
すべてのクラスによって宣言されたフィールドまたはこのクラスによって表されるインターフェースを反映するFieldオブジェクトの配列を返しますオブジェクト。このには、public、protected、default(package)アクセス、およびprivateフィールドが含まれますが、は、継承されたフィールドを除外します。返される配列内の要素はソートされておらず、特定の順序ではありません。このメソッドは、クラスまたはインターフェイスがフィールドを宣言しない場合、またはこのClassオブジェクトがプリミティブ型、配列クラス、またはvoidを表す場合、長さ0の配列を返します。
そして、すべての親クラスのすべてのフィールドが必要な場合はどうなりますか?いくつかのコードが必要です、例えばfrom https://stackoverflow.com/a/35103361/755804 :
public static List<Field> getAllModelFields(Class aClass) {
List<Field> fields = new ArrayList<>();
do {
Collections.addAll(fields, aClass.getDeclaredFields());
aClass = aClass.getSuperclass();
} while (aClass != null);
return fields;
}