リフレクションの一般的なフィールド取得値


132

リフレクションを介してフィールド値を取得しようとしています。問題は、フィールドのタイプがわからないため、値を取得するときにそれを決定する必要があることです。

このコードは、次の例外で発生します。

java.lang.Stringフィールドcom .... fieldNameをjava.lang.Stringに設定できません

Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);

Class<?> targetType = field.getType();
Object objectValue = targetType.newInstance();

Object value = field.get(objectValue);

キャストしようとしましたが、コンパイルエラーが発生します。

field.get((targetType)objectValue)

または

targetType objectValue = targetType.newInstance();

これどうやってするの?


4
APIを見ると、への引数field.get()はでobjectはなく、であるはずobjectValueです。
akaIDIOT

回答:


144

以前に答えたように、あなたは使うべきです:

Object value = field.get(objectInstance);

別の方法として、好まれることもあるが、動的にゲッターを呼び出す。コード例:

public static Object runGetter(Field field, BaseValidationObject o)
{
    // MZ: Find the correct method
    for (Method method : o.getMethods())
    {
        if ((method.getName().startsWith("get")) && (method.getName().length() == (field.getName().length() + 3)))
        {
            if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase()))
            {
                // MZ: Method found, run it
                try
                {
                    return method.invoke(o);
                }
                catch (IllegalAccessException e)
                {
                    Logger.fatal("Could not determine method: " + method.getName());
                }
                catch (InvocationTargetException e)
                {
                    Logger.fatal("Could not determine method: " + method.getName());
                }

            }
        }
    }


    return null;
}

また、クラスが別のクラスから継承する場合、Fieldを再帰的に決定する必要があることにも注意してください。たとえば、特定のクラスのすべてのフィールドをフェッチするには、

    for (Class<?> c = someClass; c != null; c = c.getSuperclass())
    {
        Field[] fields = c.getDeclaredFields();
        for (Field classField : fields)
        {
            result.add(classField);
        }
    }

1
自分でスーパークラスを反復処理する必要があることは正確には正しくないようです。c.getFields()またはc.getField()は、各実装インターフェースのフィールドを自動的に検索し、すべてのスーパークラスを再帰的に検索します。したがって、getDeclaredXからgetXに切り替えるだけで十分です。
はPrzemyslawŁadyński

3
実際、getFields()ルーチンを使用すると、すべてのスーパークラスとインターフェースのフィールドをフェッチできますが、パブリックのものだけをフェッチできます。通常、フィールドはプライベート/保護され、ゲッター/セッターを介して公開されます。
マリウス

@マリウス、パッケージBaseValidationObjectって何だろう?
randytan

@Randytan(私のプライベートコードリポジトリに含まれています)は、Objectで置き換えることができます。同じことが静的ロガー呼び出しにも当てはまります。それらを独自のロガー(インスタンス)に置き換えてください。
マリウス

@Marius objectクラスにはメソッドがありませんgetMethods()。何かアドバイスは?
randytan

127

フィールドのgetメソッドにオブジェクトを渡す必要があるので、

  Field field = object.getClass().getDeclaredField(fieldName);    
  field.setAccessible(true);
  Object value = field.get(object);

6
field.get(object)でオブジェクトを使用する必要がある理由を知っていますか?フィールド自体がそのオブジェクトから取得されますが、なぜ再び必要なのですか?
serup

18
@serupいいえ、FieldオブジェクトはClassオブジェクトに由来し、実際のインスタンスとは関係ありません。(object.getClass()このClassオブジェクトが返されます)
Dmitry Spikhalskiy

1
objectスニペットでは定義されていないため、読者はそれを使用する方法を理解できません。
Ghilteras

@Ghilterasはその場合、まだリフレクションを使用してはならず、最初に基本的なスキルを身につけるべきです🤷🏻‍♂️。リフレクションは、変数がobject操作対象のオブジェクト/インスタンスを意味することを説明しないほど高度なトピックです。私は読者が実際objectにこの答えにあるもので完全に元気であると思います。
Dmitry Spikhalskiy

@RajanPrasadそうでもない。質問に「オブジェクト」という名前の単一のオブジェクトがあります。他のオブジェクトには他の名前があります。答えは正確で、質問と質問で使用される名前に合わせて調整されているため、物事をできるだけ明確にする必要があります。それがあなたのために機能しない場合-私はそれをもっと明確にする方法がわからないので、あなたは他の答えを試すか、おそらく今のところ反射を避けるべきです
Dmitry Spikhalskiy

19

設定クラスのtoString()実装でリフレクションを使用して、クラスのメンバーと値を確認します(シンプルで迅速なデバッグ)。

私が使用している簡単なコード:

@Override
public String toString() {
    StringBuilder sb = new StringBuilder();

    Class<?> thisClass = null;
    try {
        thisClass = Class.forName(this.getClass().getName());

        Field[] aClassFields = thisClass.getDeclaredFields();
        sb.append(this.getClass().getSimpleName() + " [ ");
        for(Field f : aClassFields){
            String fName = f.getName();
            sb.append("(" + f.getType() + ") " + fName + " = " + f.get(this) + ", ");
        }
        sb.append("]");
    } catch (Exception e) {
        e.printStackTrace();
    }

    return sb.toString();
}

私も検索したので、それが誰かを助けることを願っています。


12

あなたが何を達成しようとしているのかははっきりしていませんが、コードに明らかなエラーがあることを発見しました。 Field.get()引数としてフィールドを含むオブジェクトが、そのフィールドの(可能な)値ではないことを期待しています。だからあなたは持っている必要がありfield.get(object)ます。

フィールド値を探しているように見えるので、次のように取得できます。

Object objectValue = field.get(object);

フィールドタイプをインスタンス化して、空/デフォルト値を作成する必要はありません。または私が逃した何かがあるかもしれません。


2
object定義されていない、読者は答えを適用する方法を理解できません。
Ghilteras

10
 Integer typeValue = 0;
 try {
     Class<Types> types = Types.class;
     java.lang.reflect.Field field = types.getDeclaredField("Type");
     field.setAccessible(true);
     Object value = field.get(types);
     typeValue = (Integer) value;
 } catch (Exception e) {
     e.printStackTrace();
 }

4

間違った引数でgetを呼び出しています。

そのはず:

Object value = field.get(object);

2
object定義されていない、読者は答えに例を適用する方法を理解できない
Ghilteras

2

私のソリューションをKotlinに投稿しましたが、Javaオブジェクトでも機能します。すべてのオブジェクトがこの関数を使用できるように、関数拡張を作成します。

fun Any.iterateOverComponents() {

val fields = this.javaClass.declaredFields

fields.forEachIndexed { i, field ->

    fields[i].isAccessible = true
    // get value of the fields
    val value = fields[i].get(this)

    // print result
    Log.w("Msg", "Value of Field "
            + fields[i].name
            + " is " + value)
}}

このウェブページを見てください:https : //www.geeksforgeeks.org/field-get-method-in-java-with-examples/


1
    ` 
//Here is the example I used for get the field name also the field value
//Hope This will help to someone
TestModel model = new TestModel ("MyDate", "MyTime", "OUT");
//Get All the fields of the class
 Field[] fields = model.getClass().getDeclaredFields();
//If the field is private make the field to accessible true
fields[0].setAccessible(true);
//Get the field name
  System.out.println(fields[0].getName());
//Get the field value
System.out.println(fields[0].get(model));
`
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.