Java各類反射性能對比

對各類方法實現get方法的性能進行了一個測試。java

總共有5個測試,,每一個測試都是執行1億次工具

1. 直接經過Java的get方法性能

2.經過高性能的ReflectAsm庫進行測試測試

3.經過Java Class類自帶的反射得到Method測試this

4.使用Java自帶的Property類獲取Method測試spa

5.BeanUtils的getProperty測試pwa

1 測試用Bean類

測試定義了以下一個bean類。code

public class SimpleBean {
    private String name;
    public String getName() {
        return name;
    }
    public SimpleBean setName(String name) {
        this.name = name;
    }
}

 

注意定義要嚴格遵照JavaBean規範,不然在使用和反射相關工具時會出現NoSuchMethodException異常,或者致使性能很是差,JavaBean規範中最重要的幾點以下:orm

1.類必須是public, 擁有public無參構造器,這樣可以經過反射newInstance()動態構建對象.
         String className = ...;
         Class beanClass = Class.forName(className);
         Object beanInstance = beanClass.newInstance();
2.由於反射newInstance使用的是無參構造器, 因此對象實例化和配置是分開的
3.每個property都有一個public的getter和setter方法, 命名方式是get/set+首字母大寫的property名

 

經測試在SimpleBean爲public時,1億次調用method.invoke方法:對象

javaReflectGet 100000000 times using 218 ms

而SimpleBean爲默認包可見時,1一億次調用method.invoke方法:

javaReflectGet 100000000 times using 12955 ms

 

2.測試代碼 

public class TestIterator {
    private long times = 100_000_000L;
    private SimpleBean bean;
    private String formatter = "%s %d times using %d ms";
    @Before
    public void setUp() throws Exception {
        bean = new SimpleBean();
        bean.setName("haoyifen");
    }
    //直接經過Java的get方法
    @Test
    public void directGet() {
        Stopwatch watch = Stopwatch.createStarted();
        for (long i = 0; i < times; i++) {
            bean.getName();
        }
        watch.stop();
        String result = String.format(formatter, "directGet", times, watch.elapsed(TimeUnit.MILLISECONDS));
        System.out.println(result);
    }
    //經過高性能的ReflectAsm庫進行測試,僅進行一次methodAccess獲取
    @Test
    public void reflectAsmGet() {
        MethodAccess methodAccess = MethodAccess.get(SimpleBean.class);
        Stopwatch watch = Stopwatch.createStarted();
        for (long i = 0; i < times; i++) {
            methodAccess.invoke(bean, "getName");
        }
        watch.stop();
        String result = String.format(formatter, "reflectAsmGet", times, watch.elapsed(TimeUnit.MILLISECONDS));
        System.out.println(result);
    }
    //經過Java Class類自帶的反射得到Method測試,僅進行一次method獲取
    @Test
    public void javaReflectGet() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Method getName = SimpleBean.class.getMethod("getName");
        Stopwatch watch = Stopwatch.createStarted();
        for (long i = 0; i < times; i++) {
            getName.invoke(bean);
        }
        watch.stop();
        String result = String.format(formatter, "javaReflectGet", times, watch.elapsed(TimeUnit.MILLISECONDS));
        System.out.println(result);
    }
    //使用Java自帶的Property屬性獲取Method測試,僅進行一次method獲取
    @Test
    public void propertyGet() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, IntrospectionException {
        Method method = null;
        BeanInfo beanInfo = Introspector.getBeanInfo(SimpleBean.class);
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            if (propertyDescriptor.getName().equals("name")) {
                method = propertyDescriptor.getReadMethod();
                break;
            }
        }
        Stopwatch watch = Stopwatch.createStarted();
        for (long i = 0; i < times; i++) {
           
            method.invoke(bean);
        }
        watch.stop();
        String result = String.format(formatter, "propertyGet", times, watch.elapsed(TimeUnit.MILLISECONDS));
        System.out.println(result);
    }
    //BeanUtils的getProperty測試
    @Test
    public void beanUtilsGet() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Stopwatch watch = Stopwatch.createStarted();
        for (long i = 0; i < times; i++) {
            BeanUtils.getProperty(bean, "name");
        }
        watch.stop();
        String result = String.format(formatter, "beanUtilsGet", times, watch.elapsed(TimeUnit.MILLISECONDS));
        System.out.println(result);
    }
}

 

 

3.測試結果

在4核i5-4590@3.30GHz機器上跑以上測試,通過屢次測量,基本在如下數值範圍附近,測試數據以下:

1. directGet 100000000 times using 37 ms

2. reflectAsmGet 100000000 times using 39 ms

3. javaReflectGet 100000000 times using 222 ms

4. propertyGet 100000000 times using 335 ms

5. beanUtilsGet 100000000 times using 20066 ms

 

4.結果分析

1.使用reflectAsm庫的性能能和直接調用get方法持平

2.Java自帶的反射性能大體爲直接get的1/6和1/9.

3.BeanUtils的getProperty很是的慢,爲直接get性能的1/500,爲Java自帶反射性能的1/100和1/60.

 

爲何BeanUtils的getProperty方法性能這麼慢?

相關文章
相關標籤/搜索