Java反射–类字段

时间:2020-01-09 10:35:19  来源:igfitidea点击:

使用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