2012-11-15 17 views
91

Próbuję odebrać wartość pola za pomocą odbicia. Problem polega na tym, że nie znam typu pól i decyduję o tym podczas pobierania wartości.Ogólna wartość pola refleksji Uzyskaj wartość pola

Wyniki tego kodu z tego wyjątku:

Nie można ustawić pola java.lang.String com .... fieldName do 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); 

próbowałem rzucić, ale pojawiają się błędy kompilacji:

field.get((targetType)objectValue) 

lub

targetType objectValue = targetType.newInstance(); 

Jak mogę to zrobić?

+2

Patrząc na [API] (http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Field.html), argumentem dla 'field.get()' powinno być 'object', a nie' objectValue'. – akaIDIOT

Odpowiedz

92

Jak odpowiedział wcześniej, należy użyć:

Object value = field.get(objectInstance); 

Innym sposobem, który jest czasem preferowana jest wywołanie getter dynamicznie. przykładowy kod:

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; 
} 

Należy również pamiętać, że kiedy klasa dziedziczy z innej klasy, musisz rekurencyjnie określić pole. na przykład, aby pobrać wszystkie Pola danej klasy;

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

wydaje się, że nie jest dokładnie prawdą, że musisz samemu dokonać iteracji przez super klasy. C.getFields() lub c.getField() automatycznie przeszuka pole w każdym interfejsie urządzenia i rekurencyjnie we wszystkich klasach nadrzędnych. Wystarczy więc przełączyć się na getX z getDeclaredX. –

+0

Rzeczywiście, procedura getFields() pozwoli ci pobrać pola dla wszystkich super klas i interfejsów, ale tylko te publiczne. Zazwyczaj pola są prywatne/chronione i są eksponowane za pomocą modułów pobierających/ustawiających. – Marius

+0

@Marius, czy mogę wiedzieć, co to jest pakiet 'BaseValidationObject'? – randytan

7

Chociaż nie jest dla mnie jasne, co próbujesz osiągnąć, zauważyłem oczywisty błąd w kodzie: Field.get() oczekuje, że obiekt, który zawiera pole jako argument, a nie jakaś (możliwa) wartość tego pola. Więc powinieneś mieć field.get(object).

Ponieważ pojawiają się szuka wartości pola, które można uzyskać za:

Object objectValue = field.get(object); 

Nie ma potrzeby tworzenia wystąpienia typ pola i stworzyć jakiś pusty/wartość domyślna; a może jest coś, co przeoczyłem.

+0

dziękuję, To jest mój pierwszy raz, kiedy korzystam z refleksji i tęskniłem za tym. –

76

Należy przekazać obiekt do dostać metodę dziedzinie, więc

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

czy znasz powód, dla którego obiekt ma być użyty w field.get (object) - samo pole pochodzi z tego obiektu, dlaczego potrzebuje go ponownie!? – serup

+7

@serup Nie, obiekt Field pochodzi z obiektu Class, który nie ma połączenia z rzeczywistą instancją. ('' 'object.getClass()' '' zwróci ci ten obiekt Class) –

+0

Tak ofcourse - dziękuje – serup

4

dzwonisz się ze złym argumentem.

Powinno być:

Object value = field.get(object); 
15

używam odbicia w toString() realizacja mojego preferencji Klasa zobaczyć członków klasy i wartości (proste i szybkie do debugowania).

Uproszczony kod używam:

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

Mam nadzieję, że będzie to komuś pomóc, bo ja też nie szukał.

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

Proszę dodać wyjaśnienie do swojego kodu. –

Powiązane problemy