Java反射–类字段
使用Java Reflection,我们可以获得有关类字段的信息,并在运行时获取和设置字段值。在Java Reflection API中,存在一个类java.lang.reflect.Field,该类具有用于访问字段类型,字段修饰符以及设置和获取字段值的方法。
获取字段实例
首先要获取Field类的实例,因为我们必须使用java.lang.Class的方法,因为该类是所有反射操作的入口。
有四种获取字段实例的方法
getField(String name)–返回一个Field对象,该对象表示类或者接口的公共成员字段。
getFields()–返回一个包含Field对象的数组,该对象反映了该类或者接口的所有可访问公共字段。
getDeclaredField(String name)–返回一个Field对象,该对象反映此Class对象表示的类或者接口的指定声明字段(甚至私有)。
getDeclaredFields()–返回一个Field对象数组,该数组反映由该Class对象表示的类或者接口声明的所有字段。这包括公共,受保护,默认(程序包)访问和私有字段,但不包括继承的字段。
获取有关类字段的信息– Java示例
本示例说明如何获取信息,例如类型,类的单个/所有字段的修饰符。使用的Field类的方法是
Field类的getType()方法返回该字段的声明类型。
字段类的getModifiers()方法以整数形式返回字段的修饰符。
import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Set; public class FieldReflectionDemo { public String str = "Reflection"; private int i; public boolean flag = false; public Set<String> citySet; public static void main(String[] args) { try { FieldReflectionDemo obj = new FieldReflectionDemo(); Class<?> c = obj.getClass(); // get specific field Field f = c.getField("str"); // getting field type Class<?> type = f.getType(); // getting field modifiers int mod = f.getModifiers(); System.out.println("Field name - " + f.getName()); System.out.println("Field type - " + type.getName()); System.out.println("Field modifiers - " + Modifier.toString(mod)); System.out.println("--- Getting all fields ---"); Field[] fields = c.getDeclaredFields(); for(Field field : fields) { System.out.println("Field name - " + field.getName()); System.out.println("Field type - " + field.getType()); System.out.println("Field modifiers - " + Modifier.toString(field.getModifiers())); } } catch (NoSuchFieldException | SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
输出:
Field name - str Field type - java.lang.String Field modifiers - public --- Getting all fields -- Field name - str Field type - class java.lang.String Field modifiers - public Field name - i Field type - int Field modifiers - private Field name - flag Field type - boolean Field modifiers - public Field name - citySet Field type - interface java.util.Set Field modifiers - public
获取和设置值
为了获取值,有一个get(Object obj)方法,该方法返回指定对象上此Field表示的字段的值。
对于设置值,有一个set(Object obj,Object value)方法,该方法将指定对象参数上此Field对象表示的字段设置为指定的新值。
import java.lang.reflect.Field; import java.util.Set; public class FieldReflectionDemo { public String str = "Reflection"; private int i; public boolean flag = false; public Set<String> citySet; public static void main(String[] args) { try { FieldReflectionDemo obj = new FieldReflectionDemo(); Class<?> c = obj.getClass(); // get specific field Field f = c.getField("str"); // show value - get method System.out.println("Field name- " + f.getName() + " Value- " + f.get(obj)); // set new value f.set(obj, "New Value"); System.out.println("Field name- " + f.getName() + " Value- " + f.get(obj)); } catch (IllegalAccessException | NoSuchFieldException | SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
输出:
Field name- str Value- Reflection Field name- str Value- New Value
获取和设置私有字段的值
我们甚至可以使用Reflection设置私有字段的值。为此,我们需要使用setAccesssible()方法将accessibility设置为true。
在示例中,我们有一个带有一个私有int字段i的Access类。在FieldReflectionDemo类中,我们将使用反射来访问该字段并为其设置值。如果我们未使用setAccesssible()方法设置访问标记,则会引发IllegalAccessException,如下所示。
class Access{ private int i; } public class FieldReflectionDemo { public String str = "Reflection"; public boolean flag = false; public Set<String> citySet; public static void main(String[] args) { try { Access obj = new Access(); Class<?> c = obj.getClass(); // get specific field Field f = c.getDeclaredField("i"); // show value - get method System.out.println("Field name- " + f.getName() + " Value- " + f.get(obj)); // set new value f.set(obj, 7); System.out.println("Field name- " + f.getName() + " Value- " + f.get(obj)); } catch (IllegalAccessException | NoSuchFieldException | SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
输出:
java.lang.IllegalAccessException: class com.theitroad.programs.FieldReflectionDemo cannot access a member of class com.theitroad.programs.Access with modifiers "private"
进行此更改后,再次运行,我们甚至可以访问私有字段。
Field f = c.getDeclaredField("i"); f.setAccessible(true);
输出:
Field name- i Value- 0 Field name- i Value- 7