- Get/Set field value
- Set field value with Reflection
- Get/set field value and possible exceptions
- Next chapter.
- Изменение приватного статического финального поля с помощью Java Reflection
- Change private static final field using java reflection
- Change static final field in java 12+
- Modify a private static final field in Java
- Cannot change static final field using java reflection?
- Changing final variables through reflection, why difference between static and non-static final variable
- Setting private final field via reflection fails when ctor is removed
Get/Set field value
We can get field value with reflection methods and they returns primitive types. The following lists have all methods we need to know.
- Object get(Object obj) Returns field value
- boolean getBoolean(Object obj) Gets field value as boolean.
- byte getByte(Object obj) Gets field value as byte.
- char getChar(Object obj) Gets field value as char.
- double getDouble(Object obj) Gets field value as double.
- float getFloat(Object obj) Gets field value as float.
- Type getGenericType() Returns a Type object that represents the declared type for the field represented by this Field object.
- int getInt(Object obj) Gets field value as int.
- long getLong(Object obj) Gets field value as long.
- short getShort(Object obj) Gets field value as short.
import java.awt.Rectangle; import java.lang.reflect.Field; /*java 2 s .co m*/ public class Main < public static void main(String[] args) < Rectangle r = new Rectangle(100, 325); Class c = r.getClass(); try < Field heightField = c.getField("height"); Integer heightValue = (Integer) heightField.get(r); System.out.println("Height: " + heightValue.toString()); > catch (NoSuchFieldException e) < System.out.println(e); >catch (SecurityException e) < System.out.println(e); >catch (IllegalAccessException e) < System.out.println(e); >> >
Set field value with Reflection
We can also set the value back to a field with reflection.
- void set(Object obj, Object value) Sets the field value.
- void setBoolean(Object obj, boolean z) Sets boolean field value.
- void setByte(Object obj, byte b) Sets byte field value.
- void setChar(Object obj, char c) Sets char field value.
- void setDouble(Object obj, double d) Sets double field value.
- void setFloat(Object obj, float f) Sets float field value.
- void setInt(Object obj, int i) Sets int field value.
- void setLong(Object obj, long l) Sets long field value.
- void setShort(Object obj, short s) Sets short field value.
import java.awt.Rectangle; import java.lang.reflect.Field; /* ja v a 2s. c o m*/ public class Main < public static void main(String[] args) < Rectangle r = new Rectangle(100, 325); Class c = r.getClass(); try < Field heightField = c.getField("height"); heightField.setInt(r, 1000); Integer heightValue = (Integer) heightField.get(r); System.out.println("Height: " + heightValue.toString()); > catch (NoSuchFieldException e) < System.out.println(e); >catch (SecurityException e) < System.out.println(e); >catch (IllegalAccessException e) < System.out.println(e); >> >
Get/set field value and possible exceptions
The following code gets and sets the values of instance and class fields
import java.lang.reflect.Field; /*from ja v a 2 s. c om*/ class X < public int i = 10; public static final double PI = 3.14; > public class Main < public static void main(String[] args) throws Exception < Classclazz = Class.forName("X"); X x = (X) clazz.newInstance(); Field f = clazz.getField("i"); System.out.println(f.getInt(x)); // Output: 10 f.setInt(x, 20); System.out.println(f.getInt(x)); // Output: 20 f = clazz.getField("PI"); System.out.println(f.getDouble(null)); // Output: 3.14 f.setDouble(x, 20); > >
Here is the output from the code above. The exception is for the final static field PI . public final static field defines a constant in Java and we cannot reset a value for a constant through reflection.
Next chapter.
What you will learn in the next chapter:
Изменение приватного статического финального поля с помощью Java Reflection
В Java, когда поле объявлено как private static final, это означает, что оно может быть установлено только один раз и не может быть изменено после его инициализации.
В Java, когда поле объявлено как private static final , это означает, что оно может быть установлено только один раз и не может быть изменено после его инициализации. Однако, иногда возникает необходимость изменить это поле во время выполнения программы. Одним из способов это сделать является использование Java Reflection.
Предположим, у нас есть класс MyClass с private static final полем MY_CONST :
Попытка изменить MY_CONST напрямую вызовет ошибку компиляции, поскольку это поле объявлено как final .
MyClass.MY_CONST = "New Value"; // Ошибка компиляции
Вместо этого, можно использовать Java Reflection для обхода этого ограничения. Ниже приведен код, который показывает, как это можно сделать:
Field field = MyClass.class.getDeclaredField("MY_CONST"); field.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); field.set(null, "New Value");
Таким образом, первые две строки получают ссылку на поле MY_CONST и делают его доступным. Следующие две строки убирают модификатор final у поля. В последней строке устанавливается новое значение для MY_CONST .
Однако, стоит отметить, что использование Java Reflection для изменения private static final полей — это плохая практика, которую следует избегать. Это может привести к неожиданным и труднообнаруживаемым ошибкам, нарушает принципы инкапсуляции и может нарушить безопасность. Этот метод следует использовать только в крайних случаях, когда нет других решений.
Change private static final field using java reflection
In case a field is initialized to a compile-time constant in the field declaration, changes to the field may not be visible, since uses of that final field are replaced at compile time with the compile-time constant. Thus each instance has different value of field a. For static final, all instances share the same value, and can’t be altered after first initialized.
Change static final field in java 12+
before = xxx after = it works
Changing final variables through reflection, why difference between, setAccessible(true); //EXTRA CODE //Modify the final using reflection Field modifiersField = Field.class.getDeclaredField(«modifiers»); modifiersField.
Modify a private static final field in Java
Create an Employee class that containing a private static final field2. Modify that field. Duration: 11:02
Cannot change static final field using java reflection?
You can avoid compiler inlining by making the value a result of a method call, even a dummy one.
public class Main < // value is not known at compile time, so not inlined public static final boolean FLAG = Boolean.parseBoolean("false"); static void setFinalStatic(Class clazz, String fieldName, Object newValue) throws NoSuchFieldException, IllegalAccessException < Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); Field modifiers = field.getClass().getDeclaredField("modifiers"); modifiers.setAccessible(true); modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL); field.set(null, newValue); >public static void main(String. args) throws Exception < System.out.printf("Everything is %s%n", FLAG); setFinalStatic(Main.class, "FLAG", true); System.out.printf("Everything is %s%n", FLAG); >>
Everything is false Everything is true
When accessing primitive static final fields, the Java compiler will assume that the value is a constant and inline the value instead of generating code that accesses the field. This means that the compiler will replace with the reference to the FALSE field with the value false . If you use reflection to access the field, you will see that the value of the field has actually changed.
This will not work for non-primitive fields, as the value of an object reference can not be inlined at compile time.
Java reflection to set static final field fails after previous reflection, Is there any way to change the second reflective access to ensure it succeeds in both cases? I tried looking at the Field object, and it doesn’t
Changing final variables through reflection, why difference between static and non-static final variable
FinalReflectionobj = new FinalReflection(); System.out.println(FinalReflection.stmark); System.out.println(obj.inmark); Field staticFinalField = FinalReflection.class.getDeclaredField("stmark"); Field instanceFinalField = FinalReflection.class.getDeclaredField("inmark"); staticFinalField.setAccessible(true); instanceFinalField.setAccessible(true); //EXTRA CODE //Modify the final using reflection Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(staticFinalField, staticFinalField.getModifiers() & ~Modifier.FINAL); instanceFinalField.set(obj, 100); System.out.println(obj.inmark); staticFinalField.set(FinalReflection.class, 101); System.out.println(FinalReflection.stmark);
This solution does not come without some downsides, it may not work in all cases:
In case a final field is initialized to a compile-time constant in the field declaration, changes to the final field may not be visible, since uses of that final field are replaced at compile time with the compile-time constant.
Another problem is that the specification allows aggressive optimization of final fields. Within a thread, it is permissible to reorder reads of a final field with those modifications of a final field that do not take place in the constructor. More on this is also explained in this similar question.
If the underlying field is final, the method throws an IllegalAccessException unless setAccessible(true) has succeeded for this Field object and the field is non-static.
From a JLS perspective, the exact behaviour of how reflection should work is not specified, but in JLS 17.5.4:
Normally, a field that is final and static may not be modified.
One workaround is to remove the final modifier through reflection.
For final, it can be assigned different values at runtime when initialized.
Class Test < public final int a; >Test t1 = new Test(); t1.a = 10; Test t2 = new Test(); t1.a = 20;
Thus each instance has different value of field a.
For static final, all instances share the same value, and can’t be altered after first initialized.
Class TestStatic < public static final int a; >Test t1 = new Test(); t1.a = 10; Test t2 = new Test(); t1.a = 20; // ERROR, CAN'T BE ALTERED AFTER THE FIRST INITIALIZATION.
Changing the value of final static member of a nested static class, public static void ; cls = Class.forName(«com.reflection.FinalPivateStaticMember$Test»); ; file_systems_loaded = cls.getDeclaredField(«val»);
Setting private final field via reflection fails when ctor is removed
Lets look at the Java doc for Field.set method:
If the underlying field is final, the method throws an IllegalAccessException unless setAccessible(true) has succeeded for this Field object and the field is non-static. Setting a final field in this way is meaningful only during deserialization or reconstruction of instances of classes with blank final fields , before they are made available for access by other parts of a program. Use in any other context may have unpredictable effects, including cases in which other parts of a program continue to use the original value of this field.
What this means is that in your example if you remove constructor you need to initialize the final field to some value and thus make it non blank. In that case if you change final field using reflection you can have unpredictable effects, including cases in which other parts of a program continue to use the original value of this field.
First, note that you’d get the same behavior even if the field is public , in which case you wouldn’t need to set the field accessible:
final Field field = SomeClass.class.getDeclaredField("num"); Field modField = Field.class.getDeclaredField("modifiers"); modField.setAccessible(true); modField.setInt(field, field.getModifiers() & ~Modifier.FINAL); field.set(obj, 1); System.out.println(obj.num);
This is the result of an optimization by Java compiler: the actual field num is set to 1 , but getNum ignores the value, because the compiler thinks that it’s final .
This line prints 1 even with the constructor removed (demo):
System.out.println(field.get(obj));
Java compiler notices that final int num is never assigned outside its initializer, and replaces return num with returning num ‘s initial value.
Note: Your experiment offers an excellent reason to why one should not attempt modifying fields that you declare non-modifiable.
Setting private static final field with reflection, Based on Change private static final field using Java reflection, I tried to set a private static final field.