-
1 # 修煉IT基本功
-
2 # java攻城獅
每一個Method都有一個root,不暴漏給外部,而是每次copy一個Method。
具體的反射呼叫邏輯是委託給MethodAccessor的,而accessor物件會在第一次invoke的時候才建立,是一種lazy init方式。而且預設Class類會cache method物件。目前MethodAccessor的實現有兩種,透過設定inflation,一個native方式,一種生成java bytecode方式。native方式啟動快,但執行時間長了不如java方式,個人感覺應該是java方式執行長了,jit compiler可以進行最佳化。所以JDK6的實現,在native方式中,有一個計數器,當呼叫次數達到閥值,就會轉為使用java方式。預設值是15。java方式的實現,基本和非反射方式相同。主要影響效能的問題,1是method.invoke中每次都要進行引數陣列包裝,2.在method.invoke中要進行方法可見性檢查,3在accessor的java實現方式下,invoke時會檢查引數的型別匹配。而在JDK7中methodhandle來做反射呼叫,形參和實參是準確的,所以只需要在連結方法的時候做檢查,呼叫時不用再做檢查。並且methodhandle是不可變值,所以jvm可以做激進最佳化,例如內聯。
-
3 # 寫程式設計師的程式碼
先來了解下java反射。
使用場合在編譯時根本無法知道該物件或類可能屬於哪些類,程式只依靠執行時資訊來發現該物件和類的真實資訊。
2. 主要作用
透過反射可以使程式程式碼訪問裝載到JVM 中的類的內部資訊,獲取已裝載類的屬性資訊,獲取已裝載類的方法,獲取已裝載類的構造方法資訊。
3. 反射的優點
反射提高了Java程式的靈活性和擴充套件性,降低耦合性,提高自適應能力。它允許程式建立和控制任何類的物件,無需提前硬編碼目標類;反射是其它一些常用語言,如C、C++、Fortran 或者Pascal等都不具備的。
4. Java反射技術應用領域很廣,如軟體測試等;許多流行的開源框架例如Struts、Hibernate、Spring在實現過程中都採用了該技術。
5. 反射的缺點
效能問題:使用反射基本上是一種解釋操作,用於欄位和方法接入時要遠慢於直接程式碼。因此Java反射機制主要應用在對靈活性和擴充套件性要求很高的系統框架上,普通程式不建議使用。
使用反射會模糊程式內部邏輯:程式人員希望在原始碼中看到程式的邏輯,反射等繞過了原始碼的技術,因而會帶來維護問題。反射程式碼比相應的直接程式碼更復雜。
綜上所述
java反射之所以慢,根本原因是編譯器沒法對反射相關的程式碼做最佳化。
我們都知道 Java 程式碼是需要編譯才能在虛擬機器裡執行的,但其實 Java 的編譯期是一段不確定的操作過程。因為它可能是一個前端編譯器(如 Javac)把 *.java 檔案編譯成 *.class 檔案的過程;也可能是程式執行期的即時編譯器(JIT 編譯器,Just In Time Compiler)把位元組碼檔案編譯成機器碼的過程;還可能是靜態提前編譯器(AOT 編譯器,Ahead Of Time Compiler)直接把 *.java 檔案編譯成本地機器碼的過程。
其中即時編譯器(JIT)在執行期的最佳化過程對於程式執行來說更重要,Java虛擬機器在編譯階段的程式碼最佳化就在這裡進行,由於反射涉及動態解析的型別,因此無法執行某些Java虛擬機器最佳化。因此,反射操作的效能要比非反射操作慢,因此應該避免在對效能敏感的應用程式中頻繁使用Java反射來建立物件。
回覆列表
先陳述一下結論:java的反射是慢,但是是相對於直接呼叫而言,慢也的確慢了一個數量級,不過在有些場景必須使用反射,並且在反射的時候,可以用一些手段進行人工最佳化
再說一下java反射之所以有一點慢的原因
1.java和python比起來,java是靜態語言型別,也就是說在編譯期java在編譯程式碼的時候就會進行型別的強檢驗,java會在編譯期進行程式碼最佳化,而反射是在執行時發生的,也就是說那些型別檢查,程式碼最佳化的事情放在了執行時,這個自然要耗費一點時間
2.編譯期在執行時很難做一些關於反射的最佳化,現在的編譯期還不是非常智慧,知道你用這段反射程式碼需要做什麼事情
3.再說一下,呼叫實現過程,在反射呼叫過程中,執行者叫MethodAccessor,我記得這個物件是懶載入的,也就是說有可能第一次反射呼叫耗時可能會更長一點,並且在呼叫的時候method.invoke方法還要對引數陣列進行包裝,可能涉及到引數型別適配,裝包拆包也有消耗,其實說到底,還是不知道具體的引數型別