簡體   English   中英

靜態方法和字段是否在定義它們的類的實例中占用內存?

[英]Do Static Methods and Fields take up memory in an instance of the class they are defined in?

例如,如果我要創建以下類:

public Class ExampleClass {
  
  private static String field1;
  private String field2;

  public ExampleClass(String field2) {
    this.field2 = field2;
  }

  public static staticMethodExample(String field1) {
    this.field1 = field1;
  }
}

如果我要創建ExampleClass的實例。 該實例是否包含我創建的靜態方法和/或字段的代碼?

我有一個對象將代表我數據庫中一行的一些數據。 我想從數據庫中的每一行創建這些對象的列表。 數據庫有數千行。 我正在創建的靜態方法將在將數據庫中的值放入對象構造函數之前對其進行格式化。

我不想通過將方法存儲在對象的每個實例中來膨脹代碼。 因此,如果靜態方法確實在對象的每個實例中都占用了空間,那么我寧願創建一個名稱為ExampleClassBuilder的單獨類。 並將格式化靜態方法放在那里。

不,靜態方法和字段在類的實例中不占用空間。

你在這里制造了一些混亂。 編譯程序時,每個方法(靜態或非靜態)的代碼都“存儲”在已編譯的程序中(在 Java 的情況下,在.class文件中)。 當您執行一個程序時,靜態成員- “屬於”一個類,如您問題中的field1 - 為您的整個程序分配一次。 其他“普通”類成員 - 如您問題中的field2 - 為您創建的每個新實例分配。

當你創建一個對象的新實例時,它的各種方法的代碼沒有被“分配”,因為它已經以編譯形式存在於你的程序中。

此類實例的堆上的數據大致如下*:

size (bytes) | description
--------------------------
8            | A pointer to the singleton object representing ExampleClass
8            | A pointer to the value stored in field2

就是這樣。 不存儲靜態字段。 沒有一個方法是,甚至不是實例方法! 這只是非靜態字段。 那個指向單例的指針? 只有一種數據結構代表了整個 VM 的 ExampleClass。 有 1000 個 ExampleClass 實例? 仍然只有一個。

這些大小可以更小,具體取決於 VM 配置。

那么 java 怎么知道 ExampleClass 的實例有一個名為instanceMethod的方法呢? 通過跟蹤指向描述 ExampleClass 本身的數據結構的指針,並注意到它具有該結構。 這個:

class Foo {
    public void hello() {}
}

基本上是語法糖:

class Foo {
    public static void hello(Foo receiver) {}
}

但請注意,實例方法執行動態分派,而靜態方法則不然。 這應該可以解釋為什么方法(甚至實例方法)不占用每個實例的任何“內存”。 整個班級只有一次。 同樣的技巧不能應用於實例字段。

*) 這過於簡單化了,JLS 或 JVMS 都沒有指定,但它反映了幾乎所有流行的 VM 的實際作用。

靜態變量和方法不會增加 Object 實例的大小。 這些字段和方法實際上是添加到 Class 對象中的。

否:當我們創建靜態變量或方法時,它存儲在堆上的特殊區域:元空間(對於 Java 8 和Permgen對於舊版本)。

每當一個類被加載static變量以及方法被加載到內存中時,允許任何實例(不鼓勵)或直接使用它們。 因此,任何對象都可以更改變量的值,但也可以在不創建類的實例的情況下對其進行操作。 在此處查看更多https://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html

暫無
暫無

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

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