2012-11-15 134 views
91

我想通過反射接收字段值。問題是我不知道字段的類型,必須在獲得價值的同時決定它。反射通用獲取字段值

此代碼的結果與此異常:

無法設置java.lang.String中現場COM ....字段名爲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(); 

我該怎麼做?

+2

看着[API](http://docs.oracle.com/docs/docs.html)com/javase/7/docs/api/java/lang/reflect/Field.html),'field.get()'的參數應該是'object',而不是'objectValue'。 – akaIDIOT

回答

92

像以前一樣回答,你應該使用:

Object value = field.get(objectInstance); 

的另一種方式,有時者優先,動態調用的getter。示例代碼:

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); 
     } 
    } 
+0

這似乎不完全正確,你需要自己遍歷超類。 c.getFields()或c.getField()將自動搜索每個實現接口上的字段,並通過所有超類遞歸搜索。所以只需從getDeclaredX切換到getX即可。 –

+0

事實上,getFields()例程將允許您爲所有超類和接口獲取字段,但只能獲取公共字段。通常,字段被私有/保護,並通過getter/setter公開。 – Marius

+0

@Marius,我可以知道什麼是「BaseValidationObject」包嗎? – randytan

7

儘管這不是真的我清楚你想達到什麼樣的,我在你的代碼發現了一個明顯的錯誤: Field.get()預計其包含字段作爲參數,那場不是一些(可能)值的對象。所以你應該有field.get(object)

既然你似乎是在尋找字段的值,你可以獲取爲:

Object objectValue = field.get(object); 

無需實例字段類型,並創建一些空/默認值;或者可能有我錯過的東西。

+0

謝謝,這是我第一次使用反射,我錯過了它。 –

76

你應該通過一個對象得到方法,所以

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

你知道爲什麼必須在field.get(object)中使用object的原因 - field本身來自那個對象,爲什麼它需要它呢? – serup

+7

@serup不,Field對象來自Class對象,它與您的實際實例沒有關係。 ('''object.getClass()'''會返回你這個Class對象) –

+0

Yes of course--謝謝 – serup

4

要調用用錯誤的說法得到。

它應該是:

Object value = field.get(object); 
15

我使用我的首選項類的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(); 
} 

我希望這會幫助別人,因爲我也已經搜查。

7
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(); 
} 
+0

請向您的代碼添加說明。 –

相關問題