2013-04-23 11 views
25

何かのオブジェクトを持つカスタムListを返すメソッドがあります。彼らは私にObjectとして返されます。これらのオブジェクトから特定のフィールドの値を取得する必要がありますが、オブジェクトのクラスはわかりません。Javaのリフレクション:オブジェクトからフィールド値を取得する方法、そのクラスを知らない方法

Reflecionやその他の方法でこれを行う方法はありますか?

+8

'Object.getClass()' - http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Object.html#getClass% 28%29 –

答えて

38

、あなたのフィールドがpublicですフィールド、リフレクション可能、素敵なセキュリティマネージャー)。

あなたがList<Foo>を返すためにあなたの方法を変更することができる場合イテレータは、あなたが情報を入力する与えることができるので、これは非常に容易になる:

List<Foo> list; //From your method 
for(Foo foo:list) { 
    Object fieldValue = foo.fieldName; 
} 

それとも、ジェネリック「はARENのJava 1.4のインターフェイスを消費している場合利用できるトン、しかし、あなたがリストにあるべきオブジェクトの種類を知っている...

List list; 
for(Object x: list) { 
    if(x instanceof Foo) { 
     Object fieldValue = ((Foo)x).fieldName; 
    } 
} 

ませ反射は必要ありません:)

+0

_ "利用可能な反射...(アンドロイドではない)" APIのlvl 1以降、Androidで 'reflect'パッケージを利用できました。 –

+0

1年前に私はその小さな点に間違いました。編集されました。主なポイントは残っています。ある理由でリフレクションが利用できない多くのJavaベースのプラットフォームがあります。 – Charlie

+0

@Charlie:しかし、SQLクエリから来るオブジェクトを処理する方法は、Hibernateで実行されました。複数のメソッドがある場合は、それぞれの結果に対して多くのクラスプロトタイプを作成する必要があります。そこには簡単な方法がありますか? –

4

フィールドがどのクラスにあるか分かっている場合は、リフレクションを使用してアクセスできます。この例(Groovyにありますが、メソッド呼び出しは同じです)ではFooクラスのFieldオブジェクトを取得し、オブジェクトの値はbです。それは、オブジェクトの具体的な具体的なクラスを気にする必要がないことを示します。重要なことは、フィールドがあるクラスを知っていて、そのクラスがオブジェクトの具象クラスまたはスーパークラスのいずれかであることです。

List list; // from your method 
for(Object x : list) { 
    Class<?> clazz = x.getClass(); 
    Field field = clazz.getField("fieldName"); //Note, this can throw an exception if the field doesn't exist. 
    Object fieldValue = field.get(x); 
} 

しかし、これは非常に醜いです、と私は、try-漁獲量のすべてを残し、および仮定の数は(パブリックます:単純なケースを想定し

groovy:000> class Foo { def stuff = "asdf"} 
===> true 
groovy:000> class Bar extends Foo {} 
===> true 
groovy:000> b = new Bar() 
===> [email protected] 
groovy:000> f = Foo.class.getDeclaredField('stuff') 
===> private java.lang.Object Foo.stuff 
groovy:000> f.getClass() 
===> class java.lang.reflect.Field 
groovy:000> f.setAccessible(true) 
===> null 
groovy:000> f.get(b) 
===> asdf 
+0

確かに、groovyを使っているなら、私が最後に使ったとき(~1.7時)にはb.stuffとgroovyがあなたのためにすべての反射と破壊を行うことができました...(それはキャビアまた、Java beanメソッドgetXのための構文的な砂糖を行います。 :) – Charlie

+0

@Charlie:はい、 'b.stuff'でこれはgroovyで十分です。 –

+0

これは素晴らしく、私のユースケースの大きな鍵はsetAccessibleを使っていました。これは弱いJavaの背景から来ていますが、他の言語ではより強力です。私はいくつかのリフレクションロジックを動かし、setAccessibleを追加するまで値にアクセスできなくなったときに失敗し始めました。 – Hazok

1

私はSTRON glyは、Javaジェネリックを使用して、そのリストにあるオブジェクトのタイプを指定することを推奨します。 List<Car>。あなたが車とトラックを持っているなら、List<Vehicle>のような共通のスーパークラス/インタフェースを使うことができます。

しかし、あなたは、彼らは以下の実行可能な例のようにプライベートであっても、フィールドにアクセスできるようにSpringのReflectionUtilsを使用することができます。

List<Object> list = new ArrayList<Object>(); 

list.add("some value"); 
list.add(3); 

for(Object obj : list) 
{ 
    Class<?> clazz = obj.getClass(); 

    Field field = org.springframework.util.ReflectionUtils.findField(clazz, "value"); 
    org.springframework.util.ReflectionUtils.makeAccessible(field); 

    System.out.println("value=" + field.get(obj)); 
} 

実行これは、の出力があります。

値を= [ C @ 1b67f74
値= 3

+0

Genericsはそうではありません。メソッドコードにアクセスできないためです。 – svz

+0

私が掲示した例は助けになるはずです。これは、実行時検査のためにプライベートフィールドと最終フィールドにもアクセス可能にします。 – Erich

+0

"[C @ 1b67f74"の代わりに "some value"の値を取得する方法は? –

0

、私は私のプロで同じ状況になったもう一つの方法がありますject。 私は私が知っているこの方法上記Hibernateのクエリ言語で

List<Object[]> list = HQL.list();

を解決し、私がしたので、何を私のオブジェクトが何であるかどの場所である:

for(Object[] obj : list){ 
String val = String.valueOf(obj[1]); 
int code =Integer.parseint(String.valueof(obj[0])); 
} 

あなたはと混合したオブジェクトを取得することができ、このようあなたはどのような価値があるのか​​を事前に知っておくか、知る価値を印刷するだけで確認できます。悪い英語 ために残念 私はそれは例えば、フェッチフィールドと配列項目をサポートしてい

1
public abstract class Refl { 
    /** Use: Refl.<TargetClass>get(myObject,"x.y[0].z"); */ 
    public static<T> T get(Object obj, String fieldPath) { 
     return (T) getValue(obj, fieldPath); 
    } 
    public static Object getValue(Object obj, String fieldPath) { 
     String[] fieldNames = fieldPath.split("[\\.\\[\\]]"); 
     String success = ""; 
     Object res = obj; 
     for (String fieldName : fieldNames) { 
      if (fieldName.isEmpty()) continue; 
      int index = toIndex(fieldName); 
      if (index >= 0) { 
       try { 
        res = ((Object[])res)[index]; 
       } catch (ClassCastException cce) { 
        throw new RuntimeException("cannot cast "+res.getClass()+" object "+res+" to array, path:"+success, cce); 
       } catch (IndexOutOfBoundsException iobe) { 
        throw new RuntimeException("bad index "+index+", array size "+((Object[])res).length +" object "+res +", path:"+success, iobe); 
       } 
      } else { 
       Field field = getField(res.getClass(), fieldName); 
       field.setAccessible(true); 
       try { 
        res = field.get(res); 
       } catch (Exception ee) { 
        throw new RuntimeException("cannot get value of ["+fieldName+"] from "+res.getClass()+" object "+res +", path:"+success, ee); 
       } 
      } 
      success += fieldName + "."; 
     } 
     return res; 
    } 

    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 in class " + clazz); 
    } 

    private static int toIndex(String s) { 
     int res = -1; 
     if (s != null && s.length() > 0 && Character.isDigit(s.charAt(0))) { 
      try { 
       res = Integer.parseInt(s); 
       if (res < 0) { 
        res = -1; 
       } 
      } catch (Throwable t) { 
       res = -1; 
      } 
     } 
     return res; 
    } 
} 

このヘルプを願っています:

System.out.println(""+Refl.getValue(b,"x.q[0].z.y")); 

ドットと中括弧の間に違いはありません、彼らはちょうど区切り文字であり、空のフィールド名は無視されます。

System.out.println(""+Refl.getValue(b,"x.q[0].z.y[value]")); 
System.out.println(""+Refl.getValue(b,"x.q.1.y.z.value")); 
System.out.println(""+Refl.getValue(b,"x[q.1]y]z[value")); 
関連する問題