提高Java反射速度的方法以及對setAccessable的誤解 – JAVA編程語言程序開發技術文章

mercyblitz 寫道
ouchxp 寫道


再就是在執行反射之前執行field.setAccessible(true); 也可以提高JDK反射效率


這樣可以提高效率?這個方法僅僅設置訪問標識,讓不能訪問的成員可以訪問。



keating 寫道
ouchxp 寫道
再就是在執行反射之前執行field.setAccessible(true); 也可以提高JDK反射效率


正如樓上mercyblitz所說,如private變量…


 


在此澄清一下對於setAccessable的誤解
先看一個例子
Java代碼 
import java.lang.reflect.InvocationTargetException;  
import java.lang.reflect.Method;  
 
public class Main {  
    public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {  
        Method m = A.class.getDeclaredMethod(“getName”, new Class[]{});  
        System.out.println(m.isAccessible());  
                //getName是public的,猜猜輸出是true還是false  
          
        A a = new A();  
        a.setName(“Mr Lee”);  
        long start = System.currentTimeMillis();  
        for(int i=0;i<10000000;i++){  
            m.invoke(a, new Object[]{});  
        }  
        System.out.println( “Simple              :” +(System.currentTimeMillis() – start));  
          
        m.setAccessible(true);//註意此處不同  
        long start1 = System.currentTimeMillis();  
        for(int i=0;i<10000000;i++){  
            m.invoke(a, new Object[]{});  
        }  
        System.out.println(“setAccessible(true) :”+( System.currentTimeMillis() – start1));  
    }  
}  
class A{  
    private String name;  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  


import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


public class Main {
 public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
  Method m = A.class.getDeclaredMethod(“getName”, new Class[]{});
  System.out.println(m.isAccessible());
                //getName是public的,猜猜輸出是true還是false
  
  A a = new A();
  a.setName(“Mr Lee”);
  long start = System.currentTimeMillis();
  for(int i=0;i<10000000;i++){
   m.invoke(a, new Object[]{});
  }
  System.out.println( “Simple              :” +(System.currentTimeMillis() – start));
  
  m.setAccessible(true);//註意此處不同
  long start1 = System.currentTimeMillis();
  for(int i=0;i<10000000;i++){
   m.invoke(a, new Object[]{});
  }
  System.out.println(“setAccessible(true) :”+( System.currentTimeMillis() – start1));
 }
}
class A{
 private String name;
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
}


 



測試結果


引用


false
Simple              :4969
setAccessible(true) :250


 


明顯 Accessible並不是標識方法能否訪問的. public的方法 Accessible仍為false
使用瞭method.setAccessible(true)後 性能有瞭20倍的提升


Accessable屬性是繼承自AccessibleObject 類. 功能是啟用或禁用安全檢查


JDK API中的解釋


引用


AccessibleObject 類是 Field、Method 和 Constructor 對象的基類。它提供瞭將反射的對象標記為在使用時取消默認 Java 語言訪問控制檢查的能力。對於公共成員、默認(打包)訪問成員、受保護成員和私有成員,在分別使用 Field、Method 或 Constructor 對象來設置或獲得字段、調用方法,或者創建和初始化類的新實例的時候,會執行訪問檢查。


在反射對象中設置 accessible 標志允許具有足夠特權的復雜應用程序(比如 Java Object Serialization 或其他持久性機制)以某種通常禁止使用的方式來操作對象。


setAccessible
public void setAccessible(boolean flag)
                   throws SecurityException
將此對象的 accessible 標志設置為指示的佈爾值。值為 true 則指示反射的對象在使用時應該取消 Java 語言訪問檢查。值為 false 則指示反射的對象應該實施 Java 語言訪問檢查。


 


實際上setAccessible是啟用和禁用訪問安全檢查的開關,並不是為true就能訪問為false就不能訪問


由於JDK的安全檢查耗時較多.所以通過setAccessible(true)的方式關閉安全檢查就可以達到提升反射速度的目的


Over

發佈留言