2011-08-19 68 views
11

這是一個學術演習(免責聲明)。Java反射運行時性能

我正在構建一個應用程序,它將盡可能快地從中獲利,因爲它會與其他人競爭。

我知道使用反射聲明一個類(下面的例子)將遭受巨大的懲罰,而不是標準聲明。

Class mDefinition = Class.forName("MySpecialClassString"); 
Constructor mConstructor = mDefinition.getConstructor(new Class[]{MySpecialClass.class}); 
myClass = (MySpecialClass) mConstructor.newInstance(this); 

然而,宣告myClass如果我用它以標準方式myClass.myMethod(),我也要從性能豬吃虧的還是會是一樣的,如果我宣佈以標準方式後級?

回答

14

當您第一次實例化對象時會有性能損失。一旦這個類被加載,它就像它被正常實例化一樣,並且不會有進一步的性能損失。更進一步,如果您使用反射調用方法,將會有約15倍的性能損失(默認爲Java),之後反射調用將被JVM重寫爲與靜態編譯完全相同呼叫。因此,即使重複反映的方法調用不會導致性能下降,一旦該字節碼已被JVM重新編譯。

查看這兩個鏈接,瞭解更多信息:

+0

thks的相當詳細的說明和額外的文件。在過去的幾天裏證明是有用的。 – Frankie

7

一旦這個類已經加載,你應該沒問題。開銷與檢查表示類的運行時結構相關聯等。以標準方式調用方法應該沒問題,但是如果您開始按名稱或簽名搜索方法,則會產生額外開銷。

+1

+1同意 - 應該有一個一次性的動態查找沒有很大的代價。 –

+0

@Chris我一直在進行一些測試,你對你的假設是正確的。感謝您對此進行預先清理。 – Frankie

2

克里斯湯普森的答案是關鍵。不過,我很困惑你的代碼示例。

這將動態加載類:

Class mDefinition = Class.forName("MySpecialClassString"); 

這將讓一個Contructor爲類,這會佔用同一類的實例作爲參數。另外請注意,你與MySpecialClass.class訪問類在編譯時:

Constructor mConstructor = mDefinition.getConstructor(new Class[]{MySpecialClass.class}); 

這是通過this到構造函數實例化一個MySpecialClass

myClass = (MySpecialClass) mConstructor.newInstance(this); 

基於構造函數參數,意味着什麼我們在MySpecialClass的實例方法中?很困惑。

編輯:這是接近我沒有料想到會看到:

Class<?> mDefinition = Class.forName("MySpecialClassString"); 

//constructor apparently takes this as argument 
Class<?> constructorArgType = this.getClass(); //could be ThisClassName.class 

Constructor<?> mConstructor = mDefinition.getConstructor(constructorArgType); 

MySpecialInterface mySpecialInstance = (MySpecialInterface)mConstructor.newInstance(this); 

其中MySpecialInterface是用來與您的動態加載的類交互的接口:

interface MySpecialInterface { 
    //methods used to interface with dynamically loaded classes 
} 

無論如何請讓我知道,如果我誤解或基地在這裏。

+0

你可能是對的,因爲我現在剛開始使用反射。讓我快速介紹系統的工作原理。我們有三個類:ClassA_interaction,ClassB_object和ClassC_logic ... ClassA_interaction啓動幾個ClassB_objects併爲它們提供位置。每個ClassB_object使用反射啓動一個ClassC_logic。 ClassC_logic使用'this'(ClassB_object)提供,因爲它們必須調用ClassB_object上存在的函數。 它可能是凌亂的,但工程。你會建議我採取另一種方法嗎?請花些時間看看我的代碼。 – Frankie

+0

我不得不說我沒有親自使用動態類加載,這就是爲什麼我想要某人的確認。但是,我的理解是,如果您直接在代碼中引用某個類,或者甚至可以在編譯時訪問它,則沒有必要動態加載它。然而,如果你有一個靜態加載的'Foo',它可能是一個抽象類或接口,並且你的動態加載的類擴展/實現'Foo',這將是有意義的。在你動態地加載一個類並實例化它之後,你可以將它轉換爲'Foo'並與之交互,而無需進一步反思。 –

+0

當然,'Foo'需要用抽象/接口方法聲明的形式知道你要用這​​些動態加載的類來做的所有事情。 –