部分思路來自互聯網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)); } }