Java reflection-wpływ setAccessible(true)
Używam adnotacji do dynamicznego ustawiania wartości pól w klasach. Ponieważ chcę to zrobić niezależnie od tego, czy jest to publiczne, chronione, czy prywatne, jestem wywołaniem setAccessible(true)
w obiekcie Field za każdym razem przed wywołaniem metody set()
. Moje pytanie brzmi, jaki wpływ ma wywołanie setAccessible()
na samo pole?
Mówiąc dokładniej, powiedzmy, że jest to pole prywatne i ten zestaw wywołań kodu setAccessible(true)
. Jeśli jakieś inne miejsce w kodzie było wtedy, aby pobrać to samo pole przez odbicie, czy pole będzie już dostępne? Czy metody getDeclaredFields()
i getDeclaredField()
zwracają za każdym razem nowe instancje obiektu Field?
Myślę, że innym sposobem na stwierdzenie pytania jest to, jeśli wywołam setAccessible(true)
, jak ważne jest, aby ustawić go z powrotem do pierwotnej wartości po zakończeniu?
4 answers
Za pomocą setAccessible()
zmieniasz zachowanie AccessibleObject
, tj. instancji Field
, ale nie rzeczywistego pola klasy. Oto dokumentacja (fragment):
Wartość
true
wskazuje, że odbity obiekt powinien wstrzymać kontrole kontroli dostępu języka Java, gdy jest używany
I przykład:
public class FieldAccessible {
public static class MyClass {
private String theField;
}
public static void main(String[] args) throws Exception {
MyClass myClass = new MyClass();
Field field1 = myClass.getClass().getDeclaredField("theField");
field1.setAccessible(true);
System.out.println(field1.get(myClass));
Field field2 = myClass.getClass().getDeclaredField("theField");
System.out.println(field2.get(myClass));
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-15 12:33:32
Metoda getDeclaredField
musi zwracać za każdym razem nowy obiekt, dokładnie dlatego, że obiekt ten ma zmienną flagę accessible
. Nie ma więc potrzeby resetowania flagi. Pełne szczegóły znajdziesz w ten wpis na blogu .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-17 15:41:09
Jak wskazywały inne plakaty, setAccessible
ma zastosowanie tylko do tej instancji twojego java.lang.reflect.Field
, więc ustawienie dostępności z powrotem do jej pierwotnego stanu nie jest konieczne.
Jednakże...
Jeśli chcesz, aby Twoje wywołania field.setAccessible(true)
były trwałe, musisz użyć podstawowych metod w java.lang.Class
i java.lang.reflect.Field
. Metody public facing wysyłają kopie instancji Field
, więc "zapomina" po każdym zrobieniu czegoś w rodzaju class.getField(name)
{9]}
import java.lang.reflect.*;
import sun.reflect.FieldAccessor;
public class Reflect {
private static Method privateGetDeclaredFields;
private static Method getFieldAccessor;
public static Field[] fields(Class<?> clazz) throws Exception {
return (Field[]) privateGetDeclaredFields.invoke(clazz, false);
}
public static <T> T get(Object instance, Field field) throws Exception {
return ((FieldAccessor) getFieldAccessor.invoke(field, instance)).get(instance);
}
public static void set(Object instance, Field field, Object value) throws Exception {
((FieldAccessor) getFieldAccessor.invoke(field, instance)).set(instance, value);
}
static {
try {
// These are used to access the direct Field instances instead of the copies you normally get through #getDeclaredFields.
privateGetDeclaredFields = Class.class.getDeclaredMethod("privateGetDeclaredFields", boolean.class);
privateGetDeclaredFields.setAccessible(true);
getFieldAccessor = Field.class.getDeclaredMethod("getFieldAccessor", Object.class);
getFieldAccessor.setAccessible(true);
} catch (Exception e) {
// Should only occur if the internals change.
e.printStackTrace();
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-12 00:42:43
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class PrivateVariableAcc {
public static void main(String[] args) throws Exception {
PrivateVarTest myClass = new PrivateVarTest();
Field field1 = myClass.getClass().getDeclaredField("a");
field1.setAccessible(true);
System.out.println("This is access the private field-"
+ field1.get(myClass));
Method mm = myClass.getClass().getDeclaredMethod("getA");
mm.setAccessible(true);
System.out.println("This is calling the private method-"
+ mm.invoke(myClass, null));
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-06 12:53:25