簡體   English   中英

引用類的Java類加載機制

[英]Java Class loading mechanism for referenced Classes

加載類A ,假定A的字節碼具有對許多其他類的引用。 假設A類如下所示。

class A extends B implements C,D {

    static E e;

    F f;

    A() {

      G g = new G();

    }

    void print(H h) {

    }
}

JVM是否加載A使用的所有類? 還是在類初始化之前就不用理會它們?

如果至少其中一些已加載,是否在A完成后加載它們? A's加載將暫停直到所需的類加載?

對於此問題,假定尚未加載其他任何類。 甚至是超一流的B類和CD接口。

要了解這一點,讓我們了解一些基本知識。 這將幫助任何新手了解JAVA中的延遲加載。

如果您熟悉Netscape的Web瀏覽器並且同時使用了3.x和4.x版本,那么無疑會發現Java運行時的加載方式有所不同。 如果您在Netscape 3啟動時查看啟動畫面,您會注意到它會加載各種資源,包括Java。 但是,當您啟動Netscape 4.x時,它不會加載Java運行時-它會等到您訪問包含該標記的Web頁面。 這兩種方法說明了急切的實例化(需要時將其加載)和延遲實例化(等待直到被請求之前再加載它,因為它可能永遠不需要)的技術。

這兩種方法都有缺點:一方面,如果在該會話期間未使用資源,則始終加載資源可能會浪費寶貴的內存;另一方面,如果資源在該會話期間未使用,則可能會浪費寶貴的內存。 另一方面,如果尚未加載,則需要在首次需要資源時以加載時間為代價。

將惰性實例化視為資源保護策略

Java中的延遲實例化分為兩類:

  • 延遲類加載
  • 項目清單

延遲類加載

Java運行時具有內置的類的惰性實例化。 類僅在首次引用時才加載到內存中。 (它們也可以首先通過HTTP從Web服務器加載。)

 MyUtils.classMethod();   //first call to a static class method
 Vector v = new Vector(); //first call to operator new

延遲類加載是Java運行時環境的重要功能,因為它可以在某些情況下減少內存使用。 例如,如果在會話期間從不執行程序的一部分,則永遠不會加載僅在程序的該部分中引用的類。

惰性對象創建

延遲對象的創建與延遲類的加載緊密相關。 第一次在以前尚未加載的類類型上使用new關鍵字時,Java運行時將為您加載它。 與惰性類加載相比,惰性對象的創建可以減少更多的內存使用。

為了介紹惰性對象創建的概念,讓我們看一個簡單的代碼示例,其中框架使用MessageBox來顯示錯誤消息:

   public class MyFrame extends Frame
  {
  private MessageBox mb_ = new MessageBox();
  //private helper used by this class
  private void showMessage(String message)
  {
    //set the message text
    mb_.setMessage( message );
    mb_.pack();
    mb_.show();
  }
}

在上面的示例中,當創建MyFrame的實例時,還將創建MessageBox實例mb_。 相同的規則遞歸適用。 因此,在類MessageBox的構造函數中初始化或分配的所有實例變量也將在堆外分配,依此類推。 如果MyFrame實例不用於在會話中顯示錯誤消息,則我們不必要地浪費了內存。

在這個相當簡單的示例中,我們並不會真正獲得太多收益。 但是,如果考慮一個更復雜的類,該類使用許多其他類,這些類又依次遞歸使用和實例化更多對象,則潛在的內存使用情況會更加明顯。

  public final class MyFrame extends Frame
  {
  private MessageBox mb_ ; //null, implicit
  //private helper used by this class
  private void showMessage(String message)
  {
    if(mb_==null)//first call to this method
      mb_=new MessageBox();
    //set the message text
    mb_.setMessage( message );
    mb_.pack();
    mb_.show();
  }
}

如果仔細看showMessage(),您會發現我們首先確定實例變量mb_是否等於null。 由於尚未在聲明時初始化mb_,因此Java運行時已為我們完成了此工作。 因此,我們可以安全地通過創建MessageBox實例進行操作。 以后所有對showMessage()的調用都會發現mb_不等於null,因此跳過了對象的創建並使用了現有實例。

結論 :一旦有子實體初始化,它將加載所有依賴對象。為了減少內存占用,我們應該在虛擬代理,延遲初始化等設計模式上謹慎尋找這些依賴對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM