2021.5.24:Field类——访问字段

学习自:访问字段 - 廖雪峰的官方网站

Field类型——字段类型

对任意的一个Object实例,只要我们获取了它的Class,就可以获取它的一切信息。

Class提供了以下几个方法来获取字段:

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

以上Field表示是Field类型

public class Main {
    public static void main(String[] args) throws Exception {
        Class stdClass = Student.class;
        // 获取public字段"score":
        System.out.println(stdClass.getField("score"));
        // 获取继承的public字段"name":
        System.out.println(stdClass.getField("name"));
        // 获取private字段"grade":
        System.out.println(stdClass.getDeclaredField("grade"));
    }
}

class Student extends Person {
    public int score;
    private int grade;
}

class Person {
    public String name;
}

上述代码首先获取Student的Class实例,然后,分别获取public字段继承的public字段以及private字段,打印出的Field类似:

public int Student.score
public java.lang.Person.name
private int Student.grade

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

  • getName():返回字段名称,如“name”;
  • getType():返回字段类型,也是一个Class实例,例如:String.class
  • getModifiers():返回字段修饰符,这是一个int类型变量,不同bit代表不同的含义

以String的value字段为例,它的定义是:

public final class String{
    private final byte[] value;
}

我们用反射获取该字段的信息,代码如下:

Field f = String.class.getDeclaredField("value");
f.getName(); // "value"
f.getType(); // class [B 表示byte[]类型
int m = f.getModifiers();
Modifier.isFinal(m); // true
Modifier.isPublic(m); // false
Modifier.isProtected(m); // false
Modifier.isPrivate(m); // true
Modifier.isStatic(m); // false

获取字段值

利用反射拿到字段的一个Field实例只是第一步,我们还可以拿到一个实例对应的该字段的值

例如,对于一个Person实例,我们可以先拿到name字段对应的Field,再获取这个实例的name字段的值

import java.lang.reflect.Field;

public class Main{
    public static void main(String [] args) throws Exception{
        Object p = new Person("Xiao Ming");
        Class c = p.getClass();
        Field f = c.getDeclaredField("name");
        Object value = f.get(p);
        System.out.println(value);
    }
}

class Person{
    private String name;
    public Person(String name){
        this.name=name;
    }
}

上述代码①先获取Class实例c②再获取Field实例f,然后,③用Field.get(Object)获取指定实例的指定字段的值。

运行代码,如果不出意外,会得到一个IllegalAccessException,这是因为name被定义为一个private字段。要修复错误,有两个方法:①将private修改为public在调用Object value = f.get(p);前,先写一句:

f.setAccessible(true);

调用Field.setAccessible(true)的意思是,别管这个字段是否为public,全都允许访问。

不过,我们访问字段时,通常是直接访问p.name反射是一种非常规的用法,它更多地是给工具或者底层框架来使用,目的是在不知道目标实例的任何信息的情况下,获取特定字段的值。

设置字段值:Field.set(Object,Object)

Field.set(Object,Object):设置字段值,第一个Object指定的实例第二个Object待修改的值

 

Person p = new Person("Xiao Ming");
Class c = person.getClass();
Field f = c.getDeclaredField("name");
f.setAccessible(true);
f.set(p,"Xiao Hong");

 修改非public字段,需要首先调用setAccessible(true);

 

总结

1、字段类型——Field

通过Class实例,可以获得一个class的所有字段信息,主要是四种方法:

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

获取Field对象后,可以进一步获取字段信息:

  • getName():返回字段名称,如“name”;
  • getType():返回字段类型,也是一个Class实例,例如:String.class;
  • getModifiers():返回字段修饰符,int类型,不同bit代表不同的含义

用法:

Field f = String.class.getDeclaredField("value");
f.getName(); // "value"
f.getType(); // class [B 表示byte[]类型
int m = f.getModifiers();

2、获取字段值——Field.get(obj)

Object obj = new XXX(...);
Class cls = obj.getClass();
Field f = c.getDeclaredField(name);
Object value = f.get(obj);

如果要获取private字段值,还要在get前添加一句:

f.setAccessible(true);

3、设置字段值——Field.set( obj , value )

Object obj = new XXX(...);
Class cls = obj.getClass();
Field f = cls.getDeclaredField( name );
f.set(obj , value);

同样,要修改非public字段值,也要写:

f.setAccessible(true);

 

posted @ 2021-05-24 15:04  ShineLe  阅读(327)  评论(0)    收藏  举报