2016-12-14 65 views
2

我有這樣一類:字段和代碼中的可選類型,是否安全?

class Environment { 

    somelib.SomeType someOptionalDep = null; 

    public void doSomething() { 
     boolean found = false; 
     try { 
      Class.forName("somelib.SomeType"); 
      found = true; 
     } catch (ClassNotFoundException e) { 
     } 
     if (found) { 
      someOptionalDep = new somelib.SomeType(); 
      // ... 
     } 
    } 

} 

somelib是一個可選包:存在於編譯時,但是從底罐中排除。事實上,這段代碼沒有依賴性(Debian 8上的Oracle Java HotSpot 1.8.0_111),但這真的很安全嗎?

注:知道,我可以在分離類包裝可選的功能,但是這是對子級在某些情況下,太複雜了。

編輯:

NoClassDefFoundError的Oracle文檔:

如果Java虛擬機或ClassLoader實例試圖在類的定義中加載時拋出(作爲普通方法的一部分調用或作爲使用new表達式創建新實例的一部分),並且不能找到該類的定義。

當編譯當前正在執行的類時存在搜索到的類定義,但定義無法找到。

不幸的是,它沒有明確聲明關於聲明或已加載但未執行的代碼。

+2

有什麼意義?爲什麼不抓住'NoClassDefFoundError'? – shmosel

+0

是一個可能不存在類型的字段聲明是安全的嗎? –

回答

1

不,這是行不通的。當你的課程被加載時,虛擬機也會尋找SomeType,並拋出一個錯誤。要做到這一點,正確的方法是創建一個接口,你還包括在base.jar,已經SOMETYPE實現接口,然後執行:

class Environment { 
    SomeInterface someOptionalDep = null; 
    public void doSomething() { 
     try { 
     Class c = Class.forName("somelib.SomeType");   
     someOptionalDep = c.newInstance(); 
     } catch (ClassNotFoundException, InstantiationException, IllegalAccessException e) { 
     } 
    } 
} 
+0

OP表示它確實爲他工作。 – shmosel

+0

我懷疑它可以工作,除非環境類不是首先加載。 –

+0

@Roberto Attias:正如@shmosel所說,我已經在Debian 8上使用Oracle Java HotSpot 1.8.0_111進行了嘗試,並且工作。 「someOptionalDep」存儲一個第三方庫類的實例,它通常沒有可移植的接口(可能是Object someOptionalDep)。 –

1

我相信你的首要問題在評論

陳述

字段聲明是否安全且可能不存在類型?

和通過安全你似乎意味着「不會導致NoClassDefFoundError」。

在回答問題本身之前,我想說你最好不要這樣做。在你的代碼中有一個不存在的類型會使它不必要的複雜 - 這是安全的。可選的依賴關係最好由一種將業務邏輯與依賴關係分開的網關處理。如Roberto Attias所建議的其他界面就是一個例子。您也可以將自己的接口引入到實現中:將所有調用委託給可選的依賴項,而另一個則無所作爲。


從技術上講,答案是肯定的

JVM傾向於儘可能懶惰地執行某些操作 - 特別是類加載。當一個類被加載時,JVM只會加載它的超類和超接口,而不是代碼中使用的其他類型。

此外,即使讀寫一個不存在類型的字段也不是而是本身會引發類加載(和NoClassDefFoundError)。這是可能的,因爲

  • 如果你正在讀一個字段,則類加載可以被推遲,直到你真正使用它
  • 如果你正在寫一個非空值,那麼你已經加載的類型如果你正在寫一個空的字段,則該類型並不重要(因爲空可以分配到任意值)

BTW,這同樣適用於參數和返回值創建實例

  • 方法。

  • +0

    「可選依賴關係最好由一種將您的業務邏輯與依賴關係分離的網關處理。」 - 總的來說很好,但國際海事組織這個特例是例外情況之一。我的包是對一些依賴於平臺的資源的輕量級抽象,不能在其中實現繁忙邏輯。 –

    +0

    @DávidHorváth從這個和你的其他評論看來,'Environment'可能已經被用於類似於我試圖描述的內容,即它安全地封裝對'SomeType'的訪問,將其提供給業務邏輯並且什麼都不做。如果是這樣,那沒關係。否則,這也可以,因爲這是你的慎重選擇,你是唯一可以決定的人選。 –