反射2--Field,简单的实现和部分源码分析

Posted lvdandan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反射2--Field,简单的实现和部分源码分析相关的知识,希望对你有一定的参考价值。

>部分思路来自互联网 ### 反射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)); } } ```

以上是关于反射2--Field,简单的实现和部分源码分析的主要内容,如果未能解决你的问题,请参考以下文章

gomock 源码分析

Sprig AOP原理及源码解析

MyBatis源码分析-基础支持层反射模块Reflector/ReflectorFactory

RateLimiter 源码分析(Guava 和 Sentinel 实现)

RateLimiter 源码分析(Guava 和 Sentinel 实现)

0004JDK源码分析之如何反射类的私有属性和私有方法