私は継承されたメンバーを経由class.getDeclaredFields();
してプライベートメンバーにアクセスする方法を見つけましたが class.getFields()
、私は継承されたプライベートフィールドを探しています。どうすればこれを達成できますか?
私は継承されたメンバーを経由class.getDeclaredFields();
してプライベートメンバーにアクセスする方法を見つけましたが class.getFields()
、私は継承されたプライベートフィールドを探しています。どうすればこれを達成できますか?
回答:
これはそれを解決する方法を示すはずです:
import java.lang.reflect.Field;
class Super {
private int i = 5;
}
public class B extends Super {
public static void main(String[] args) throws Exception {
B b = new B();
Field f = b.getClass().getSuperclass().getDeclaredField("i");
f.setAccessible(true);
System.out.println(f.get(b));
}
}
(またはClass.getDeclaredFields
、すべてのフィールドの配列の場合。)
出力:
5
getSuperclass()
到達null
するまで再帰できます。
getDeclaredFields()[0]
かgetDeclaredField("i")
ではなく、繰り返し[0]
、次の二つの文で配列アクセスを?
getDeclaredFields
。回答を更新しました。
ここでの最善のアプローチは、ビジターパターンを使用して、クラスとすべてのスーパークラスのすべてのフィールドを検索し、それらに対してコールバックアクションを実行することです。
Springには、それを実行する優れたUtilityクラスReflectionUtils
があります。それは、コールバックですべてのスーパークラスのすべてのフィールドをループするメソッドを定義します。ReflectionUtils.doWithFields()
ターゲットクラスのすべてのフィールドで指定されたコールバックを呼び出し、クラス階層を上に向かって、宣言されたすべてのフィールドを取得します。
パラメータ:
-clazz-分析するターゲットクラス-fc-
各フィールドに対して呼び出す
コールバック-ff-コールバックを適用するフィールドを決定するフィルター
ReflectionUtils.doWithFields(RoleUnresolvedList.class,
new FieldCallback(){
@Override
public void doWith(final Field field) throws IllegalArgumentException,
IllegalAccessException{
System.out.println("Found field " + field + " in type "
+ field.getDeclaringClass());
}
},
new FieldFilter(){
@Override
public boolean matches(final Field field){
final int modifiers = field.getModifiers();
// no static fields please
return !Modifier.isStatic(modifiers);
}
});
タイプクラスjavax.management.relation.RoleUnresolvedListで
フィールドprivate一時ブール値javax.management.relation.RoleUnresolvedList.typeSafeが見つかりましたタイプクラスjavax.management.relation.RoleUnresolvedListでフィールドプライベート一時ブール値javax.management.relation.RoleUnresolvedList.taintedが
見つかりました型クラスjava.util.ArrayList
Foundフィールドのプライベートトランジェントjava.lang.Object [] java.util.ArrayList.elementData型クラスjava.util.ArrayListのプライベートint java.util.ArrayList.size
フィールドprotectedトランジェントint Java。タイプクラスjava.util.AbstractListのutil.AbstractList.modCount
これでできます:
private List<Field> getInheritedPrivateFields(Class<?> type) {
List<Field> result = new ArrayList<Field>();
Class<?> i = type;
while (i != null && i != Object.class) {
Collections.addAll(result, i.getDeclaredFields());
i = i.getSuperclass();
}
return result;
}
EclEmmaのようなコードカバレッジツールを使用する場合は、注意が必要です。これらのツールは、各クラスに非表示フィールドを追加します。EclEmmaの場合、これらのフィールドは合成とマークされ、次のようにフィルターで除外できます。
private List<Field> getInheritedPrivateFields(Class<?> type) {
List<Field> result = new ArrayList<Field>();
Class<?> i = type;
while (i != null && i != Object.class) {
for (Field field : i.getDeclaredFields()) {
if (!field.isSynthetic()) {
result.add(field);
}
}
i = i.getSuperclass();
}
return result;
}
public static Field getField(Class<?> clazz, String fieldName) {
Class<?> tmpClass = clazz;
do {
try {
Field f = tmpClass.getDeclaredField(fieldName);
return f;
} catch (NoSuchFieldException e) {
tmpClass = tmpClass.getSuperclass();
}
} while (tmpClass != null);
throw new RuntimeException("Field '" + fieldName
+ "' not found on class " + clazz);
}
(この回答に基づく)
実際、私は複雑なタイプの階層を使用しているため、ソリューションは完全ではありません。すべてのプライベート継承フィールドを取得するには、再帰呼び出しを行う必要があります。これが私の解決策です
/**
* Return the set of fields declared at all level of class hierachy
*/
public Vector<Field> getAllFields(Class clazz) {
return getAllFieldsRec(clazz, new Vector<Field>());
}
private Vector<Field> getAllFieldsRec(Class clazz, Vector<Field> vector) {
Class superClazz = clazz.getSuperclass();
if(superClazz != null){
getAllFieldsRec(superClazz, vector);
}
vector.addAll(toVector(clazz.getDeclaredFields()));
return vector;
}
Model Citizenでブループリントの継承フィールドのサポートを追加する必要がありました。クラスのフィールド+継承されたフィールドを取得するために少し簡潔なこのメソッドを導出しました。
private List<Field> getAllFields(Class clazz) {
List<Field> fields = new ArrayList<Field>();
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
Class superClazz = clazz.getSuperclass();
if(superClazz != null){
fields.addAll(getAllFields(superClazz));
}
return fields;
}
private static Field getField(Class<?> clazz, String fieldName) {
Class<?> tmpClass = clazz;
do {
for ( Field field : tmpClass.getDeclaredFields() ) {
String candidateName = field.getName();
if ( ! candidateName.equals(fieldName) ) {
continue;
}
field.setAccessible(true);
return field;
}
tmpClass = tmpClass.getSuperclass();
} while ( clazz != null );
throw new RuntimeException("Field '" + fieldName +
"' not found on class " + clazz);
}