反射访问字段
对于任何一个Object实例,只要我们获取了JVM中与之对应的Class实例,就可以通过该实例获取到该Object实例的一切信息。
Class类提供了一下几个方法来获取字段:
- Field getField(String name):通过字段名获取public修饰的字段(包括父类继承的字段)
- Field getDeclaredField(String name):通过字段名获取当前类中的字段(不包括父类)
- Field[] getFields():获取所有public修饰的字段(包括父类)
- Field[] getDeclaredFields():获取该类中所有字段(不包括父类)
public class ReflectField{
public static void main(String[] args){
Class stdClazz = Student.class;
//获取当前类public字段
System.out.println(stdClazz.getField("score"))
//获取父类的public字段
System.out.println(stdClazz.getField("name"))
//获取private字段
System.out.println(stdClazz.getDeclaredField("grade"))
}
}
class Student extends Person{
public int scroe;//分数
private int grade;//年级
public Student(String name) {
super(name);
}
}
class Person{
public String name;//姓名
public Person(String name) {
this.name = name;
}
}
输出结果:
public int com.example.factory_compiler.reflect.Student.score
public java.lang.String com.example.factory_compiler.reflect.Person.name
private int com.example.factory_compiler.reflect.Student.grade
一个Field对象包含了一个字段的所有信息:
- getName():返回字段名称
/**
* Returns the name of the field represented by this {@code Field} object.
*/
public String getName() {
return name;
}
- getType():返回字段类型,也是一个Class实例,eg:String.class
/**
* Returns a {@code Class} object that identifies the
* declared type for the field represented by this
* {@code Field} object.
*
* @return a {@code Class} object identifying the declared
* type of the field represented by this object
*/
public Class<?> getType() {
return type;
}
- getModifiers():返回字段的修饰符,它是一个int值,不同的bit表示不同的含义。
Field f = Student.class.getDeclaredField("score");
f.getName();//"score"
f.getType();//int
int m = f.getModifiers();
Modifier.isFinal(m);
Modifier.isPublic(m);
Modifier.isProtected(m);
Modifier.isPirvate(m);
Modifier.isStatic(m);
获取字段值
利用反射拿到字段的Field实例只是第一步,我们还可以拿到一个实例对应的该字段的值:
public class ReflectField{
public static void main(String[] args){
Student student = new Student("张三")
Class cls = student.getClass();
Field f = cls.getField("name");
//f.setAccessible(true);
Object value = f.get(student)zhu;
//f.set(student,"李四");//修改反射字段的值
System.out.println(value);//张山
}
}
注意: 如果访问的字段被定义为一个private的字段,直接访问时会出现IllegalAccessException,所以当访问一个被修饰为private的字段时,先在之前写一句
field.setAccessible(true);//一律允许访问
通过Field实例可以读取或设置某个对象的字段,如果存在访问限制,要首先调用setAccessible(true)来访问非public字段(如果JVM运行期存在SecurityManager,那么它会根据规则进行检查,有可能阻止setAccessible(true),例如,某个SecurityManager可能不允许对Java核心库的类调用该方法,这样可以保证JVM核心库的安全)。