簡體   English   中英

Java在內存中的含義是什么

[英]What does Java look like in memory

我是java新手,還在學習。 我抓住了內心和匿名課程。 現在我有一個關於java在內存中的樣子,分配對象,定義類等的技術問題。

就像當一個字段是一個在外部類和內部類中定義的對象時,內存的樣子。 靜態類看起來與非靜態不同嗎?

我只需要一個視覺參考。

多謝你們

細節在實現中(不是規范)。 然而,實現通常遵循非常簡單的模式。 Java中的大多數內存布局都非常簡單明了。 我的術語可能與Java術語不匹配,因為我沒有做很多Java編程。

通常,對象以指向其vtable的指針開始,然后有一堆字段。 字段是基本類型(int / bool / float)或指向對象的指針。 這就是對象。 (類也是對象。)空指針就像C一樣,它們是無效的,不像Python,其中None是一個對象。

在內部類中,有一個額外的隱藏字段,指向外部類的實例。 這是內部類訪問外部類中的數據的方式。 匿名類的工作方式相同。 靜態方法只是類的方法而不是實例上的方法。

vtable是所有魔法發生的地方。 每個類都有自己的vtable在所有對象之間共享。 vtable具有關於類的信息,例如其實例的大小以及字段的布局方式。 垃圾收集器使用此信息。 vtable還有一個指向該類實現的所有方法的指針。 當您調用方法時,運行時首先從對象中獲取vtable指針,然后將方法指針從vtable中取出,然后調用該方法並將該對象作為隱式參數傳遞給該方法。 它與C ++類似,但實現起來要簡單得多。 如果方法或類是“最終的”,則可以跳過該過程。

我知道Java並沒有真正的“指針”,它有“符號句柄”或類似的東西,但常見的實現只使用普通的舊指針。

歡迎來到Java世界。 與C語言不同,語言構造和內存表示幾乎一對一地映射,Java稍微復雜一些。

首先,當人們談論Java時,它可能意味着兩件事:Java-the-language和Java-the-platform。 在這里,我將Java稱為Java編程語言。 用Java編寫的代碼首先被編譯為字節碼,Java虛擬機的機器代碼。 如果您對Java語言的詳細信息感興趣,請參閱Java語言規范 對於JVM,有Java虛擬機規范

當我有一個字段是一個在外部類和內部類中定義的對象時,內存是什么樣的。

我將這解釋為Java虛擬機中的內存布局是什么樣的,因為物理布局取決於JVM的實現。 為此,我瀏覽了Java虛擬機的結構

與Java語言一樣,Java虛擬機也可以使用兩種類型: 基本類型引用類型 相應地,有兩種值可以存儲在變量中,作為參數傳遞,由方法返回,並對其進行操作: 原始值參考值

Java虛擬機期望幾乎所有類型檢查都在編譯時完成,而不是由Java虛擬機本身完成。 特別是,不需要標記數據或以其他方式檢查數據以確定類型。

....

對對象的引用被視為具有Java虛擬機類型reference 類型reference值可以被認為是指向對象的指針。

所以答案似乎是兩個字段看起來完全一樣: reference

就像當一個字段是一個在外部類和內部類中定義的對象時,內存的樣子。 靜態類看起來與非靜態不同嗎?

非靜態內部(或匿名)類的實例將引用用於實例化它的外部類實例。 這允許內部類中的方法引用封閉類中聲明的實例級成員。 通常,此引用作為構造函數中的隱藏額外參數傳遞給內部類。 但是如果使用反射來創建內部類實例,則必須顯式提供該額外參數。

(注意,當匿名類使用實例化它的方法范圍內的locals /參數時,會使用不同的機制...)

如果您需要更多詳細信息,可以使用javap來反匯編一些簡單示例類的字節碼。

我只需要一個視覺參考。

對不起,我不做漂亮的照片:-)

靜態(嵌套)類的工作方式與頂級類的工作方式完全相同。 唯一的區別是它的名字有另一個以它為前綴的類名。 (如果查看已編譯的.class文件,您實際上會看到對於名為Nested的類嵌套在名為Outer的類中,您將獲得類似“Outer $ Nested.class”的內容。)

內部類有一個隱藏字段,它是對其外部類的包含實例的引用。 當你寫:

class Outer {
  final int x;

  class Nested {
    int y;

    Nested(int y) {
      this.y = y;
    }

    int bar() {
      return x + y;
    }
  }

  void foo() {
    Nested n = new Nested(5);
  }
}

就像你寫的那樣:

class Outer {
  final int x;

  static class Nested {
    Outer outer;
    int y;

    Nested(Outer outer, int y) {
      this.outer = outer;
      this.y = y;
    }

    int bar() {
      return outer.x + y;
    }
  }

  void foo() {
    Nested n = new Nested(this, 5);
  }
}

隱藏字段的名稱(我在這里稱之為“外部”)對你來說是隱藏的,雖然你可以通過在內部類中說Outer.this來引用它(其中Outer是你的外部類的名字,當然)。 同樣,請注意,當內部類中的方法引用外部類中的某些內容時,該引用實際上是通過對外部類的隱藏引用。

關於訪問控制(例如:private)如何與嵌套/內部類一起工作,還有一些額外的復雜性,但這並不會真正影響您所詢問的“內存”問題。

public class I {
    class inner {
        public void ctor() {};
    }
}

看起來像是一樣,你可以使用JAD

class I$inner {

  // Field descriptor #6 LI;
  final synthetic I this$0;

  // Method descriptor #8 (LI;)V
  // Stack: 2, Locals: 2
  I$inner(I arg0);
     0  aload_0 [this]
     1  aload_1
     2  putfield I$inner.this$0 : I [10]
     5  aload_0 [this]
     6  invokespecial java.lang.Object() [12]
     9  return
      Line numbers:
        [pc: 0, line: 3]
      Local variable table:
        [pc: 0, pc: 10] local: this index: 0 type: I.inner

  // Method descriptor #14 ()V
  // Stack: 0, Locals: 1
  public void ctor();
    0  return
      Line numbers:
        [pc: 0, line: 4]
      Local variable table:
        [pc: 0, pc: 1] local: this index: 0 type: I.inner
}

作為一個hexdump,它將從0xcafebabe開始

暫無
暫無

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

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