Field类及其用法
Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。同样的道理,我们可以通过Class类的提供的方法来获取代表字段信息的Field对象,Class类与Field对象相关方法如下:
方法返回值 | 方法名称 | 方法说明 |
---|---|---|
Field |
getDeclaredField(String name) |
获取指定name名称的(包含private修饰的)字段,不包括继承的字段 |
Field[] |
getDeclaredField() |
获取Class对象所表示的类或接口的所有(包含private修饰的)字段,不包括继承的字段 |
Field |
getField(String name) |
获取指定name名称、具有public修饰的字段,包含继承字段 |
Field[] |
getField() |
获取修饰符为public的字段,包含继承字段 |
下面的代码演示了上述方法的使用过程
public class ReflectField {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class<?> clazz = Class.forName("reflect.Student");
//获取指定字段名称的Field类,注意字段修饰符必须为public而且存在该字段,
// 否则抛NoSuchFieldException
Field field = clazz.getField("age");
System.out.println("field:"+field);
//获取所有修饰符为public的字段,包含父类字段,注意修饰符为public才会获取
Field fields[] = clazz.getFields();
for (Field f:fields) {
System.out.println("f:"+f.getDeclaringClass());
}
System.out.println("================getDeclaredFields====================");
//获取当前类所字段(包含private字段),注意不包含父类的字段
Field fields2[] = clazz.getDeclaredFields();
for (Field f:fields2) {
System.out.println("f2:"+f.getDeclaringClass());
}
//获取指定字段名称的Field类,可以是任意修饰符的自动,注意不包含父类的字段
Field field2 = clazz.getDeclaredField("desc");
System.out.println("field2:"+field2);
}
}
class Person{
public int age;
public String name;
//省略set和get方法
}
class Student extends Person{
public String desc;
private int score;
//省略set和get方法
}
输出结果:
field:public int reflect.Person.age
f:public java.lang.String reflect.Student.desc
f:public int reflect.Person.age
f:public java.lang.String reflect.Person.name
================getDeclaredFields====================
f2:public java.lang.String reflect.Student.desc
f2:private int reflect.Student.score
field2:public java.lang.String reflect.Student.desc
上述方法需要注意的是,如果我们不期望获取其父类的字段,则需使用Class类的getDeclaredField/getDeclaredFields方法来获取字段即可,倘若需要连带获取到父类的字段,那么请使用Class类的getField/getFields,但是也只能获取到public修饰的的字段,无法获取父类的私有字段。下面将通过Field类本身的方法对指定类属性赋值,代码演示如下:
//获取Class对象引用
Class<?> clazz = Class.forName("reflect.Student");
Student st= (Student) clazz.newInstance();
//获取父类public字段并赋值
Field ageField = clazz.getField("age");
ageField.set(st,18);
Field nameField = clazz.getField("name");
nameField.set(st,"Lily");
//只获取当前类的字段,不获取父类的字段
Field descField = clazz.getDeclaredField("desc");
descField.set(st,"I am student");
Field scoreField = clazz.getDeclaredField("score");
//设置可访问,score是private的
scoreField.setAccessible(true);
scoreField.set(st,88);
System.out.println(st.toString());
//输出结果:Student{age=18, name='Lily ,desc='I am student', score=88}
//获取字段值
System.out.println(scoreField.get(st));
// 88
其中的set(Object obj, Object value)
方法是Field类本身的方法,用于设置字段的值,而get(Object obj)
则是获取字段的值,当然关于Field类还有其他常用的方法如下:
方法返回值 | 方法名称 | 方法说明 |
---|---|---|
void |
set(Object obj, Object value) |
将指定对象变量上此 Field 对象表示的字段设置为指定的新值。 |
Object |
get(Object obj) |
返回指定对象上此 Field 表示的字段的值 |
Class<?> |
getType() |
返回一个 Class 对象,它标识了此Field 对象所表示字段的声明类型。 |
boolean |
isEnumConstant() |
如果此字段表示枚举类型的元素则返回 true;否则返回 false |
String |
toGenericString() |
返回一个描述此 Field(包括其一般类型)的字符串 |
String |
getName() |
返回此 Field 对象表示的字段的名称 |
Class<?> |
getDeclaringClass() |
返回表示类或接口的 Class 对象,该类或接口声明由此 Field 对象表示的字段 |
void | setAccessible(boolean flag) | 将此对象的 accessible 标志设置为指示的布尔值,即设置其可访问性 |
上述方法可能是较为常用的,事实上在设置值的方法上,Field类还提供了专门针对基本数据类型的方法,如setInt()/getInt()、setBoolean()/getBoolean、setChar()/getChar()等等方法,这里就不全部列出了,需要时查API文档即可。需要特别注意的是被final关键字修饰的Field字段是安全的,在运行时可以接收任何修改,但最终其实际值是不会发生改变的。