2010-08-15 64 views
12

是否有保證(默認,系統)Java類加載程序不是嘗試加載正在運行的代碼中未引用的類?一對夫婦的我是什麼意思的例子:Java類加載器是否保證不加載未使用的類?

  • 我使用的是framework.jar我知道包含另一個library.jar參考「在IT方面的類,但我使用的是沒有按框架只有這樣一部分」 t包含這些引用。離開library.jar是否安全?
  • 靜態塊在第一次加載類時運行。如果沒有運行代碼包含對特定類的引用,是否確定它的靜態塊未運行?

快速測試似乎與上述假設的工作,一下子就沒有太大的意義無論如何加載未使用的類,但沒有任何保證對此有何看法?

此外:似乎我的「靜態塊運行時,一個類首次加載」上面的語句有些不正確。這是絕對可能的加載類(一件事)沒有運行他們(另一件事)。所以我對這兩種情況都很感興趣。保證有關班級沒有收到加載,而沒有收到運行

回答

7

沒有這樣的保證關於類的加載。

但是,我們保證靜態塊不會過早運行。觸發類初始化的事件在JLS 12.4.1中指定。

類或接口類型T將緊接在以下中的任何一個的第一次出現之前被初始化:

  • T是一個類並且創建T的實例。
  • T是一個類,由T聲明的靜態方法被調用。
  • 指定由T聲明的靜態字段。
  • 使用由T聲明的靜態字段,該字段不是常量變量(§4.12.4)。
  • T是一個頂級類,並且執行一個在T中詞彙嵌套的斷言語句(第14.10節)。

1 - 觀察到電流生成Java實現不裝載類不必要,但是這並不能保證。唯一的保證是它在官方規格書中寫的。

1

我不認爲有任何這樣的保證。首先,我看到了代碼掃描程序,它們在應用程序啓動過程中處理整個程序包層次結構/ JAR中的批註;他們會馬上違反這個假設。

這是爲什麼?你通常經過高度可控的系統加載後,所以任何重要的地方都會在某處你想要強制它的地方...

1

拉類的東西是從Java字節代碼引用它們(它可能再次拉入其他課程)。如果你運行的類沒有任何對類X的引用,它將不會被加載。

但請注意,有更新的方法來註冊例如服務通過META-INF。這些類也需要加載。

您可以隨時運行「-verbose」以在加載類時查看這些類 - 該順序清楚地表明它們在需要時加載。

+0

AFAIK,這不僅僅是這裏的「參考」,還包括使用。只要不使用類(即在執行字節碼指令中引用),它就不會被加載。當然,這不是規範所保證的,但任何自我尊重的JVM都是這樣表現的。 – sasuke 2010-08-15 18:23:54

4

化java specification狀態

加載過程由 類的ClassLoader和它的子類 實施。 ClassLoader的不同子類可以實現不同的 加載策略。特別地,類加載器可以緩存二進制表示 類和接口,基於預期的使用預取它們 或將相關類組加載在一起。

所以類加載器可以自由預取類文件。

類或接口類型T將被 的 以下中的任何一個的 第一次出現之前立即初始化:

  • T是一個類並且創建T的實例。
  • T是一個類,由T聲明的靜態方法被調用。
  • 指定由T聲明的靜態字段。
  • 使用由T聲明的靜態字段,對字段的引用不是編譯時常量(第15.28節)。編譯時常量的引用必須在編譯時解析爲編譯時常量的副本,所以這樣的字段的使用永遠不會導致初始化。

僅當第一次使用該類時,纔會執行靜態塊。

+1

+1用於「根據預期使用率預取它們,或將一組相關類加載在一起」。所以沒有關於不加載任何東西的保證。 – 2010-08-18 13:24:41

1

如果您不使用反射,那麼您可以使用死代碼刪除工具(如ProGuard)靜態檢查使用哪些類。它會分析你的代碼並確定所有使用的類。在此基礎上,它將刪除未使用的代碼,包括庫中未使用的代碼。

如果您的代碼或庫使用反射來加載類,那麼您將需要運行應用程序的全面覆蓋測試並記錄所有加載的類,這些類指示ProGuard保留。

+0

我覺得Joonas項目對依賴於library.jar的framework.jar有依賴性。然而,Joonas認爲他的項目不依賴於library.jar。 ProGuard能否真正驗證斷言? – emory 2010-08-16 02:32:09

0

沒有其他海報提及的保證。但是你的問題和你的關注並不相互關聯。對於你離開library.jar,你不需要這樣的保證。

有許多框架可以在運行時發現其他框架的存在與否。例如:Commons-logging發現了一堆其他框架。 Spring Web Flow在運行時發現腳本框架是什麼(例如它是OGNL)。這些框架顯然是使用所有依賴框架編譯的,但它們不必在運行時存在。

因此,在運行時將library.jar放出是完全可以接受的。

0

是的。

想想以下幾點。如果將以下代碼添加到library.jar類:

public ShutDown {static { System.exit(-1); }} 

該代碼將不會被系統默認自動加載,因爲沒有任何現有的代碼有一個參考或知道的ShutDown類的,也沒有一個加載它的方式,而Java類加載器不會試圖從jar中加載隨機類。

如果您仔細閱讀它們,則前面的答案介紹了加載類的方式,但其中沒有一個包含「如果jar中有類,它將加載」某種類型。

+0

我想你是混淆類加載和類初始化。 – 2016-09-15 07:56:40