1. 首先明确一点,getDeclaredFiled()只能取得本类独有的成员字段,getField()能取得本类独有的成员字段+父类的成员字段 但 这些都只能是public的. 所谓不可取得即是不可见,NoSuchField.
比如现在有两个类:
public class Animal {
public String name;
protected double appetite;
int age;
private String habitat;
public Animal() {
}
public Animal(String name, double appetite, int age, String habitat) {
this.name = name;
this.appetite = appetite;
this.age = age;
this.habitat = habitat;
}
}
public class Person extends Animal{
public double height;
protected double weight;
String hobby;
private double salary;
public Person(){}
public Person(double height, double weight, String hobby, double salary) {
this.height = height;
this.weight = weight;
this.hobby = hobby;
this.salary = salary;
}
}
测试的包结构如下:
先看同一包内的Demo1:
package demo.reflection1;
import org.junit.Before;
import org.junit.Test;
import java.lang.reflect.Field;
/**
* @Author Mr.Lee
* @create 2021/12/16 16:01
*/
public class Demo1 {
Person person;
Class<? extends Person> clazz;
@Before
public void prepare(){
person = new Person(183.5, 140, "游泳", 10000.0);
clazz = person.getClass();
}
@Test
// getDeclaredField()只能find本类独有的成员字段
public void test1() throws NoSuchFieldException {
System.out.println("-------------本类独有的成员字段都能被found:正常-------------");
Field height = clazz.getDeclaredField("height");
System.out.println(height);
Field weight = clazz.getDeclaredField("weight");
System.out.println(weight);
Field hobby = clazz.getDeclaredField("hobby");
System.out.println(hobby);
Field salary = clazz.getDeclaredField("salary");
System.out.println(salary);
System.out.println("-----------父类的任意一个:报错,因为都不能被found----------------");
Field name = clazz.getDeclaredField("name");
System.out.println(name);
Field appetite = clazz.getDeclaredField("appetite");
System.out.println(appetite);
Field age = clazz.getDeclaredField("age");
System.out.println(age);
Field habitat = clazz.getDeclaredField("habitat");
System.out.println(habitat);
}
}
@Test
// getField()能find本类独有的成员字段+父类的成员字段 但 这些都只能是public的.
public void test2() throws NoSuchFieldException {
System.out.println("------------public的都能被found:正常-----------");
Field height = clazz.getField("height");
System.out.println(height);
Field name = clazz.getField("name");
System.out.println(name);
System.out.println("----------非public的任意一个:报错,因为都不能被found-----------");
Field weight = clazz.getField("weight");
Field hobby = clazz.getField("hobby");
Field salary = clazz.getField("salary");
Field appetite = clazz.getField("appetite");
Field age = clazz.getField("age");
Field habitat = clazz.getField("habitat");
}
2.前面getDeclaredField()和getField()区分完了,接着看setAccissible()的作用.
先看同包下的Demo1:
@Test
// 以getDeclaredField()为例,展示 setAccessible()的访问控制:
// Demo1和Person同包,正常情况下只能够access public,protected,缺省 成员字段 ; 但通过 字段.setAccessible(true)可以access private成员字段
public void test3_1() throws NoSuchFieldException, IllegalAccessException {
System.out.println("---------权限够:正常--------");
Field height = clazz.getDeclaredField("height");
System.out.println(height.get(person));
Field weight = clazz.getDeclaredField("weight");
System.out.println(weight.get(person));
Field hobby = clazz.getDeclaredField("hobby");
System.out.println(hobby.get(person));
System.out.println("-------权限不够,但setAccessible(true):正常--------");
Field salary2 = clazz.getDeclaredField("salary");
salary2.setAccessible(true);
System.out.println(salary2.get(person));
System.out.println("--------权限不够:报错,因为IllegalAccess-------");
Field salary = clazz.getDeclaredField("salary");
System.out.println(salary.get(person));
}
Demo2: 不同包且无继承关系,故protected,缺省权限的字段也就不能访问了
package demo.reflection2;
import demo.reflection1.Person;
import org.junit.Before;
import org.junit.Test;
import java.lang.reflect.Field;
/**
* @Author Mr.Lee
* @create 2021/12/16 16:04
*/
public class Demo2 {
Person person;
Class<? extends Person> clazz;
@Before
public void prepare(){
person = new Person(183.5, 140, "游泳", 10000.0);
clazz = person.getClass();
}
@Test
public void test3_2() throws NoSuchFieldException, IllegalAccessException {
System.out.println("---------权限够:正常--------");
Field height = clazz.getDeclaredField("height");
System.out.println(height.get(person));
System.out.println("-------权限不够,但setAccessible(true):正常--------");
Field salary2 = clazz.getDeclaredField("salary");
salary2.setAccessible(true);
System.out.println(salary2.get(person));
Field weight2 = clazz.getDeclaredField("weight");
weight2.setAccessible(true);
System.out.println(weight2.get(person));
Field hobby2 = clazz.getDeclaredField("hobby");
hobby2.setAccessible(true);
System.out.println(hobby2.get(person));
System.out.println("--------权限不够:报错,因为不能access -------");
Field weight = clazz.getDeclaredField("weight");
System.out.println(weight.get(person));
Field hobby = clazz.getDeclaredField("hobby");
System.out.println(hobby.get(person));
Field salary = clazz.getDeclaredField("salary");
System.out.println(salary.get(person));
}
}
}
3.关于found和access: 最后细心的你们一定发现了1中直接输出 getDecalredField() ,2中却输出的 字getDecalredField().get() .
2中讨论的权限 access的问题,对于getDecalredField()对所有的能被found的字段都能取得不存在illegalAccess,这样就起不到测试权限的作用.而getDecalredField().get()是取实例对象的字段值,可能存在illegalAccess.(可以理解为getDecalredField()返回的Field对象本身就是public的,而getDecalredField().get()返回的实例对象的成员字段权限取决于他自身)