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方法性能这么慢?

相关文章
相关标签/搜索