Java 反射調用的一種最佳化__Java

來源:互聯網
上載者:User

      寫一些Java架構的時候,經常需要通過反射get或者set某個bean的field,比較普通的做法是擷取field後調用java.lang.reflect.Field.get(Object),但每次都這樣調用,能否有最佳化的空間呢。

 

答案是有。

第一種:

      由於每次都是重複的調用,所以想到了緩衝每個bean的field,但這樣做還是不夠,所以想到了寫一個code generator。通過產生代碼的方式,get或者set每個bean的時候直接調用該bean的getter或者setter,這個實現聽起來很牛逼,其實就是用asm產生一個類在用一個classloader載入進來每次調用直接invoke就可以了。

      可單純為了一個反射調用做這麼多,總感覺是大炮打了蚊子。

 

第二種:

      多謝@RednaxelaFX   的指點,找到了更簡單的做法:sun.misc.Unsafe

      使用也非常的簡單:首先通過sun.misc.Unsafe.objectFieldOffset(Field) 擷取field的offset,然後使用sun.misc.Unsafe.getObject(Object, long)擷取某個執行個體上的field的值。

      簡單的測試代碼如下:

 

import java.io.Serializable; import java.lang.reflect.Field; import sun.misc.Unsafe; /** * @author haitao.yao Dec 14, 2010 */ public class ReflectionCompare { private static final int count = 10000000; /** * @param args */ public static void main(String[] args) { long duration = testIntCommon(); System.out.println("int common test for " + count + " times, duration: " + duration); duration = testUnsafe(); System.out.println("int unsafe test for " + count + " times, duration: " + duration); } private static long testUnsafe() { long start = System.currentTimeMillis(); sun.misc.Unsafe unsafe = getUnsafe(); int temp = count; Field field = getIntField(); long offset = unsafe.objectFieldOffset(field); while (temp-- > 0) { unsafe.getInt(new TestBean(), offset); } return System.currentTimeMillis() - start; } private static long testIntCommon() { long start = System.currentTimeMillis(); int temp = count; getIntField().setAccessible(true); while (temp-- > 0) { TestBean bean = new TestBean(); try { getIntField().get(bean); } catch (Exception e) { e.printStackTrace(); } } return System.currentTimeMillis() - start; } private static final sun.misc.Unsafe unsafe; static { sun.misc.Unsafe value = null; try { Class<?> clazz = Class.forName("sun.misc.Unsafe"); Field field = clazz.getDeclaredField("theUnsafe"); field.setAccessible(true); value = (Unsafe) field.get(null); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error to get theUnsafe", e); } unsafe = value; } public static final sun.misc.Unsafe getUnsafe() { return unsafe; } private static final Field intField; private static final Field stringField; static { try { intField = TestBean.class.getDeclaredField("age"); stringField = TestBean.class.getDeclaredField("name"); } catch (Exception e) { e.printStackTrace(); throw new IllegalStateException("failed to init testbean field", e); } } public static final Field getIntField() { return intField; } public static final Field getStringField() { return stringField; } /** * @author haitao.yao * Dec 14, 2010 */ static class TestBean implements Serializable{ /** * */ private static final long serialVersionUID = -5994966479456252766L; private String name; private int age; /** * @return the name */ public String getName() { return name; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @return the age */ public int getAge() { return age; } /** * @param age the age to set */ public void setAge(int age) { this.age = age; } } }

 

      通過測試發現,效率是普通java.lang.reflect.Field.get(Object)的3倍,當然,效能這個東西,還是自己測試了放心。

      這樣做有一個不好的地方:sun.misc.Unsafe在sun的包裡,預設情況下,eclipse編譯會報錯,在Window->Preference->Java->Compiler->Errors/Warnings->Deprecated and restricted API -> Forbidden Reference 修改成Warning或者Ignore就可以了。由於Unsafe在JDK中很多的類庫中都在使用,架構代碼中使用還是很安全的,如果需要api變動,JDK原始碼的修改工作量比我們的大多了 :-0

 

      至於第一種方法,雖然麻煩,有時間還是可以嘗試一下的,有時間了寫一下。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.