JavaリフレクションのgetFieldsとgetDeclaredFieldsの違いは何ですか


194

Javaリフレクションを使用する場合のgetFieldsメソッドとメソッドの違いについて少し混乱getDeclaredFieldsしています。

getDeclaredFieldsクラスのすべてのフィールドへのアクセスを提供し、getFieldsパブリックフィールドのみを返すこと を読みました。これが事実なら、なぜあなたはいつもいつも使用しないのですgetDeclaredFieldsか?

誰かがこれについて詳しく説明して、2つの方法の違いを説明できますか?また、いつ/なぜ一方を他方で使用したいのですか?


3
getFieldスーパークラスから継承されたフィールドを取得できますが、取得getDeclaredFieldできません。getDeclaredField関数を呼び出すクラスに制限されます。
user2336315 2013

@ user2336315正解ですが、getFieldプライベートメンバーにはアクセスできません
Madbreaks

回答:


258

getFields()

publicクラス階層全体のすべてのフィールド。

getDeclaredFields()

すべてのフィールドは、アクセシビリティに関係なく、現在のクラスに対してのみであり、現在のクラスが継承している可能性のある基本クラスではありません。

階層の上のすべてのフィールドを取得するために、次の関数を記述しました。

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するために、グアバから来ています。

更新

ちなみに、上記のコードはReflectionUtilsのLibExプロジェクトのGitHubで公開されています。


8
すばらしい答えですが、スーパークラスのプライベートフィールドは、現在のクラスのインスタンスField#getや同様のメソッドでは使用できないことに注意してください。言い換えれば、このアプローチで、通常のコンパイルとは異なり、現在のクラスがスーパークラスのプライベートインターフェイスにアクセスすることはできません。
FThompson 2013

4
真@Vulcanコードを経由して範囲を変更するためにリフレクションを使用するように書かれていない限りsetAccessible、ノーSecurity Managerは所定の位置にありません
ジョン・B

少しだけ、「(スコープに関係なく)」ではなく「(アクセシビリティに関係なく)」でなければなりません。すべてのフィールドのスコープは同じです。つまり、クラスの本体です。
yshavit 2013

@yshavitありがとう。更新しました。
John B

1
そうではありません。ためprivateのフィールドだけを介してアクセスすることができるgetDeclaredFieldsクラス固有です。各フィールド(タイプと名前が同じであっても)は異なるFieldインスタンスになります。
ジョンB

7

すでに述べたように、はそれを呼び出す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);
}

まったく見つからない場合でもエラーをスローするようにわずかに変更try try { field = clazz.getDeclaredField(name); } catch (NoSuchFieldException e) { clazz = clazz.getSuperclass(); if(clazz==null){ throw e; } }
Sven Dhaens 2017

5

public Field[] getFields() throws SecurityException

このClassオブジェクトが表すクラスまたはインターフェイスのすべてのアクセス可能なパブリックフィールドを反映するFieldオブジェクトを含む配列を返します。返される配列の要素は並べ替えられておらず、特定の順序でもありません。このメソッドは、クラスまたはインターフェイスにアクセス可能なパブリックフィールドがない場合、または配列クラス、プリミティブ型、またはvoidを表す場合、長さ0の配列を返します。

具体的には、このClassオブジェクトがクラスを表す場合、このメソッドはこのクラスとそのすべてのスーパークラスのパブリックフィールドを返しますこのClassオブジェクトがインターフェースを表す場合、このメソッドはこのインターフェースとそのすべてのスーパーインターフェースのフィールドを返します。

配列クラスの暗黙の長さフィールドは、このメソッドには反映されません。ユーザーコードは、配列を操作するためにクラスArrayのメソッドを使用する必要があります。


public Field[] getDeclaredFields() throws SecurityException

このClassオブジェクトが表すクラスまたはインタフェースによって宣言されたすべてのフィールドを反映するFieldオブジェクトの配列を返します。これには、パブリック、保護、デフォルト(パッケージ)アクセス、およびプライベートフィールドが含まれますが、継承されたフィールドは含まれません。返される配列の要素は並べ替えられておらず、特定の順序でもありません。このメソッドは、クラスまたはインターフェイスがフィールドを宣言しない場合、またはこのClassオブジェクトがプリミティブ型、配列クラス、またはvoidを表す場合、長さ0の配列を返します。


また、すべての親クラスのすべてのフィールドが必要な場合はどうなりますか?いくつかのコードが必要です、例えば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;
}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.