>部分思路来自互联网
### 反射2–Field

“`
public class Person {

private int age;
public String name;

{
age = 11;
name = “yoyoyo”;
}

static {
System.out.println(“Hello”);
}

public Person() {}

public Person(String name) {
this.name = name;
System.out.println(this.name);
}

public int getAge() {
return age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
“`

### 反射获取参数

“`
public class reflectTest {
public static void main(String[] args) throws Exception {
//1.加载class,实例化对象
Person person = (Person)Class.forName(“POJO.Person”).newInstance();

//2.获取参数
//getDeclaredField可以获取类(不包括超类)中所有作用域(修饰符),因此可以获得private int age
Field field = person.getClass().getDeclaredField(“age”);
//getField可以获取类或超类的公有域(public),所以无法获取private int age,但可以获得public String name;
//Field field = person.getClass().getField(“name”);

//3.当访问private作用域的参数时,需要setAccessible(true),反射的对象在使用时取消Java语言访问检查
//public的参数可以不写setAccessible(true)
field.setAccessible(true);

//field.getModifiers()获得参数作用域
//field.getType()获取参数类型
//field.getName()获取参数名字
//field.get(obj)获取值,返回为object
System.out.println(“first field:”+Modifier.toString(field.getModifiers())+” “+field.getType()+” “+field.getName()+” = “+field.get(person));
//为field设置新值,如果是基本类型,会自动解包
field.set(person,10010);
System.out.println(“last field:”+Modifier.toString(field.getModifiers())+” “+field.getType()+” “+field.getName()+” = “+field.get(person));
}
}
“`

###注意:并不是说private的Accessible是false,而public的Accessible就是true(事实是false),实际上field.isAccessible()是获取此对象的可访问标志的值,说人话就是“是否允许get,set”。

“`
@CallerSensitive
public Field getField(String name)
throws NoSuchFieldException, SecurityException {

//checkMemberAccess进行java的安全验证和访问权限检查,
//Reflection.getCallerClass()可以获取到调用这个方法的类
//PUBLIC允许反射
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);

Field field = getField0(name);
if (field == null) {
throw new NoSuchFieldException(name);
}
return field;
}
“`

“`
private void checkMemberAccess(int which, Class caller, boolean checkProxyInterfaces) {

//java安全管理器,进行访问控制和权限控制,防止运行未知java程序被恶意代码对系统产生影响
//https://docs.oracle.com/javase/8/docs/api/java/lang/SecurityManager.html
final SecurityManager s = System.getSecurityManager();

//异常则返回null
if (s != null) {

//获取调用类的加载器
final ClassLoader ccl = ClassLoader.getClassLoader(caller);
//调用native本地方法,返回classLoader
final ClassLoader cl = getClassLoader0();

//PUBLIC=0,DECLARED=1,Member.DECLARED可以禁止反射
if (which != Member.PUBLIC) {

//如果classLoader和本地获取的不一致
if (ccl != cl) {

//验证安全管理器是否有权限
//SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION指运行时权限 “可以访问以声明的类成员”
//RuntimePermission(“accessDeclaredMembers”);
s.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
}
}
//验证类是否有包权限
this.checkPackageAccess(ccl, checkProxyInterfaces);
}
}
“`

“`
private Field getField0(String name) throws NoSuchFieldException {
Field res;
// 搜索声明的公共字段
if ((res = searchFields(privateGetDeclaredFields(true), name)) != null) {
return res;
}
// 递归搜索接口
Class[] interfaces = getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
Class c = interfaces[i];
if ((res = c.getField0(name)) != null) {
return res;
}
}
// 递归搜索父类
if (!isInterface()) {
Class c = getSuperclass();
if (c != null) {
if ((res = c.getField0(name)) != null) {
return res;
}
}
}
return null;
}
“`

#####题外话,关于反射的速度区别
先说结论,“(在常规条件下,也就是我的例子的情况下)setAccessible(true)将关闭java的安全检查,大幅度提升反射速度”。
“`
public class reflectSpeed {
public static void main(String[] args) throws Exception{
SecurityManager sm = new SecurityManager();
sm.checkMemberAccess(Person.class, Member.DECLARED);

Person person = (Person)Class.forName(“main.java.Person”).newInstance();
person.setName(“firstName”);

Method method = person.getClass().getMethod(“getName”);

//getName是public,所以不需要setAccessible(true)
long start = System.currentTimeMillis();
for(int i = 0;i<10000000;i++){
method.invoke(person);
}
System.out.println(“simple:”+(System.currentTimeMillis()-start));

//看一下setAccessible(true)之后的耗时
method.setAccessible(true);
long start1 = System.currentTimeMillis();
for(int i=0;i<10000000;i++){
method.invoke(person);
}
System.out.println(“setAccessible(true):”+(System.currentTimeMillis()-start1));

//当然不用反射的耗时也作为对比
long start2 = System.currentTimeMillis();
for(int i=0;i<10000000;i++){
person.getName();
}
System.out.println(“getName:”+(System.currentTimeMillis()-start2));
}
}
“`

版权声明:本文为lvdandan原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/lvdandan/p/10949919.html