部分思路来自互联网html
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)); } }
@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的安全检查,大幅度提高反射速度”。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)); } }