對各類方法實現get方法的性能進行了一個測試。java
總共有5個測試,,每一個測試都是執行1億次工具
1. 直接經過Java的get方法性能
2.經過高性能的ReflectAsm庫進行測試測試
3.經過Java Class類自帶的反射得到Method測試this
4.使用Java自帶的Property類獲取Method測試spa
5.BeanUtils的getProperty測試pwa
測試定義了以下一個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
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); } }
在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
1.使用reflectAsm庫的性能能和直接調用get方法持平
2.Java自帶的反射性能大體爲直接get的1/6和1/9.
3.BeanUtils的getProperty很是的慢,爲直接get性能的1/500,爲Java自帶反射性能的1/100和1/60.
爲何BeanUtils的getProperty方法性能這麼慢?