[英]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.