在我們平常的工作或面試中,都會經常遇到「反射」這個知識點,透過「反射」我們可以動態的獲取到物件的資訊以及靈活的呼叫物件方法等,但是在使用的同時又伴隨著另一種聲音的出現,那就是「反射」很慢,要少用。難道反射真的很慢?那跟我們平時正常創建物件呼叫方法比慢多少? 估計很多人都沒去測試過,只是」道聽途說「。下面我們就直接透過一些測試案例來直觀的感受一下」反射「。
正文
準備測試物件
下面先定義一個測試的類別TestUser,只有id跟name屬性,以及它們的getter/setter方法,另外還有一個自定義的sayHi方法。
public class TestUser { private Integer id; private String name; public String sayHi(){ return "hi"; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
測試創建100萬個物件
// 通过普通方式创建TestUser对象@Testpublic void testCommon(){ long start = System.currentTimeMillis(); TestUser user = null; int i = 0; while(i<1000000){ ++i; user = new TestUser(); } long end = System.currentTimeMillis(); System.out.println("普通对象创建耗时:"+(end - start ) + "ms"); }//普通对象创建耗时:10ms
// 通过反射方式创建TestUser对象@Testpublic void testReflexNoCache() throws Exception { long start = System.currentTimeMillis(); TestUser user = null; int i = 0; while(i<1000000){ ++i; user = (TestUser) Class.forName("ReflexDemo.TestUser").newInstance(); } long end = System.currentTimeMillis(); System.out.println("无缓存反射创建对象耗时:"+(end - start ) + "ms"); }//无缓存反射创建对象耗时:926ms
在上面這兩個測試方法中,筆者各自測了5次,把他們消耗的時間取了一個平均值,在輸出結果中可以看到一個是10ms,一個是926ms,在創建100W個物件的情況下,反射居然慢了90倍左右。 wtf?差距居然這麼大?難道反射真的這麼慢?下面筆者換一種反射的姿勢,繼續測試一下,看看結果如何?
// 通过缓存反射方式创建TestUser对象@Testpublic void testReflexWithCache() throws Exception { long start = System.currentTimeMillis(); TestUser user = null; Class rUserClass = Class.forName("RefleDemo.TestUser"); int i = 0; while(i<1000000){ ++i; user = (TestUser) rUserClass.newInstance(); } long end = System.currentTimeMillis(); System.out.println("通过缓存反射创建对象耗时:"+(end - start ) + "ms"); }//通过缓存反射创建对象耗时:41ms
其實透過程式碼我們可以發現,是Class.forName這個方法比較耗時,它實際上呼叫了一個本地方法,透過這個方法來要求JVM尋找並載入指定的類別。所以我們在專案中使用的時候,可以把Class.forName回傳的Class物件快取起來,下次使用的時候直接從快取裡面獲取,這樣就極大的提高了獲取Class的效率。同理,在我們獲取Constructor、Method等物件的時候也可以快取起來使用,避免每次使用時再來耗費時間創建。
測試反射呼叫方法
@Testpublic void testReflexMethod() throws Exception { long start = System.currentTimeMillis(); Class testUserClass = Class.forName("RefleDemo.TestUser"); TestUser testUser = (TestUser) testUserClass.newInstance(); Method method = testUserClass.getMethod("sayHi"); int i = 0; while(i<100000000){ ++i; method.invoke(testUser); } long end = System.currentTimeMillis(); System.out.println("反射调用方法耗时:"+(end - start ) + "ms"); }//反射调用方法耗时:330ms
@Testpublic void testReflexMethod() throws Exception { long start = System.currentTimeMillis(); Class testUserClass = Class.forName("RefleDemo.TestUser"); TestUser testUser = (TestUser) testUserClass.newInstance(); Method method = testUserClass.getMethod("sayHi"); int i = 0; while(i<100000000){ ++i; method.setAccessible(true); method.invoke(testUser); } long end = System.currentTimeMillis(); System.out.println("setAccessible=true 反射调用方法耗时:"+(end - start ) + "ms"); }//setAccessible=true 反射调用方法耗时:188ms
這裡我們反射呼叫sayHi方法1億次,在呼叫了method.setAccessible(true)後,發現快了將近一半。查看API可以了解到,jdk在設定獲取字段,呼叫方法的時候會執行安全存取檢查,而此類操作會比較耗時,所以透過setAccessible(true)的方式可以關閉安全檢查,從而提升反射效率。
極致的反射
除了上面的手段,還有沒有辦法更極致的使用反射呢?這裡介紹一個高效能反射工具包ReflectASM。它是透過字節碼產生的方式來實現的反射機制,下面是一個跟java反射的效能比較。
結語
最後總結一下,為了更好的使用反射,我們應該在專案啟動的時候將反射所需要的相關配置及資料載入進記憶體中,在運行階段都從快取中取這些元資料進行反射操作。大家也不用懼怕反射,虛擬機在不斷的優化,只要我們方法用的對,它並沒有」傳聞「中的那麼慢,當我們對性能有極致追求的時候,可以考慮透過三方包,直接對字節碼進行操作。
相關教學:Java影片教學
以上是怎樣提高使用Java反射的效率的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

禪工作室 13.0.1
強大的PHP整合開發環境