JAVA-通过反射获取任意类的字段


一、获取Class实例

要通过反射来获取类的信息,首先要获取到Class实例,获取Class实例的方法有三种:

  1. 通过class的静态变量class获取

    Class cls = User.class;
    
  2. 通过实例变量的getClass()方法获取

    User user = new User();
    Class cls = user.getClass();
    
  3. 知道getClass()的完整类名,可以通过静态方法Class.foName()获取

    Class cls = Class.forName("完整类名");
    

(一)通过Class实例创建对应类型的实例

  • 如果获取到了一个Class实例,通过该Class实例来创建对应类型的实例:

    // 获取String的Class实例:
    Class cls = User.class;
    // 创建一个String实例:
    User user = (User) cls.newInstance();
    

通过Class.newInstance()可以创建类的实例,局限是:只能调用public的无参数构造方法。带参数的构造方法或者非public的构造方法都无法通过Class.newInstance()调用。

二、字段和字段值

(一)获取字段

Class类提供了以下几个方法来获取Field

  • Field getField(name):根据字段名获取某个public的field(包括父类)
  • Field getDeclaredField(name):根据字段名获取当前类的某个field(不包括父类)
  • Field[] getFields():获取所有public的field(包括父类)
  • Field[] getDeclaredFields():获取当前类的所有field(不包括父类)

在上一篇介绍反射概念文章的最后简单的使用Field:

Class cls = User.class;

System.out.println(cls.getName());
System.out.println(cls.getPackage());
System.out.println(cls.getSuperclass());

// 获取所有public的field(包括父类)
Field[] fields = cls.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
    System.out.println(fields[i]);
}

// 获取当前类的field(不包括父类)
Field[] fields2 = cls.getFields();
for (int i = 0; i < fields2.length; i++) {
    System.out.println(fields2[i]);
}

Field对象包含了一个字段的所有信息。

  • getName():返回字段名称;
  • getType():返回字段类型,也是一个Class实例;
  • getModifiers():返回字段的修饰符,是一个int,不同的位表示不同的含义。

比如获取User的name字段:

Field field = User.class.getDeclaredField("name");
System.out.println(field.getName());
System.out.println(field.getType());

(二)获取字段值

因为Field的get()方法只能接收Object作为参数,所以在得到参数t后要将其转为Object

public  void getFieldValue(T t) throws NoSuchFieldException, IllegalAccessException {
    Object obj = (Object)t;
    Class cls = obj.getClass();
    Field field = cls.getDeclaredField("name");
    //因为main类一般是无法访问private字段的,所以需要设置可访问权限为true
    field.setAccessible(true);
    Object name = field.get(obj);
    System.out.println(name);
}

获取到字段值后,自然可以设置字段值。通过Field.set(Object, Object)方法可以设置字段值。

public  void setFieldValue(T t) throws NoSuchFieldException, IllegalAccessException {
    Object obj = (Object) t;
    Class cls = obj.getClass();
    Field field = cls.getDeclaredField("name");
    field.setAccessible(true);
    System.out.println(field.get(obj));
    field.set(obj, "abcd");
    System.out.println(field.get(obj));
}