簡體   English   中英

為什么不是每個方法都是 static 方法?

[英]Why isn't every method is a static method?

如果非static函數被復制到每個具有該方法的 object 的堆中,那么為什么默認情況下不是 Java static中的所有方法? 為什么要這樣浪費所有堆 memory?

圖形解釋對我理解這一點更有幫助。

Static 方法不能訪問對象的實例成員變量... 沒有state,沒有OOP。

您的問題是關於過程編程和面向對象編程之間的比較。 http://en.wikipedia.org/wiki/Procedural_programming#Comparison_with_object-oriented_programming OO 與程序的主要動機是擁有能夠自行執行操作的數據結構。

關於memory分配的假設,方法沒有復制到每個object,因為Java不支持動態類型修改。 例如,如果 object 是 Foo 類型,那么它將具有 Foo 類型聲明的所有方法。 在不更改類型本身的情況下,無法將新方法添加到 Foo 的實例。 每當在 object 上調用方法時,它都會在后台作為過程運行。

每當你運行這個:

foo.say( "Hello, world!" );

Java 實際上做了這樣的事情:

  1. 創建字符串“Hello, world!”
  2. 查找為foo聲明的類型。
  3. 在該類型中查找具有簽名say(String)的方法。
  4. 使用foo對象的實例 state 運行該方法。

因為方法維護自己的 state,所以任何非靜態方法都可以通過將 object 實例作為方法參數傳入,以 static 的方式實現。 事實上,上面的第 4 步很可能是由 Java 編譯器以這種方式實現的。

通常,Java 方法不是通過每 object 一次將方法復制到堆上來實現的。相反,方法通常使用稱為虛擬 function 表(或“vtable”)的東西來實現。 這個想法是每個方法都有一個副本,無論它是 static 還是非靜態方法,指向這些方法的指針都放在一個表中。 堆中的每個 object 然后存儲一個指向其 object 類型的 vtable 的指針。 這意味着任何堆 object 的大小都不取決於 object 擁有的方法數量。 事實上,具有 100 個方法的 object 與具有 1 個方法的 object 的大小相同(假設它們具有相同的字段)。 每個只存儲一個指向其 object 類型的 vtable 的指針,其中只有一個副本。

這種優化最初用於 C++ 以支持快速虛函數,此后被用於許多其他面向對象的語言。 它允許對象很小,但支持動態調度。

換句話說,默認情況下,方法不需要是static ,因為它們不會影響堆中對象的大小。 創建一個 object 不是功能多的對象耗時更長,還是占用堆空間多。

這是一些對象布局的可能圖表(對 ASCII 藝術表示歉意。),假設我們有兩個類。 A 和 B,然后在 memory 中:這些類型的對象可能如下所示:

   A                      vtable for A
 +-------------+        +---------------+
 | vtable ptr  | --+->  | method one    |
 +-------------+   |    +---------------+
 |             |   |    | method two    |
 | fields of A |   |    +---------------+
 |             |   |    |     ...       |
 +-------------+   |    +----------------
                   |    | method N      |
   A               |    +---------------+
 +-------------+   |
 | vtable ptr  |---+
 +-------------+
 |             |
 | fields of A |
 |             |
 +-------------+

   B                  vtable for B
 +-------------+     +------------+
 | vtable ptr  | --> | method one |
 +-------------+     +------------+
 |             |     | method two |
 | fields of B |     +------------+
 |             |     |    ...     |
 +-------------+     +------------+
                     | method M   |
                     +------------+

請注意 A 類型的兩個對象如何共享相同的 vtable,以及 A 類型和 B 類型的對象如何僅為其 vtable 指針使用相同數量的空間,即使它們具有不同數量的方法。

因為如果每個方法都是 static java 就不是面向對象的了。

你需要在不同的對象上調用一個方法,因為它們有不同的 state。

至於 memory - 每個 static 調用也會進入堆棧。

該方法的代碼不在堆棧上,它在堆的一部分(永久代,垃圾收集器特例)。 在堆棧上只有方法的局部變量(和類似的運行時數據,如返回地址)位於。

這與它們是 static 還是非靜態方法無關。

此外,不會為 class 的每個 object 復制該方法的代碼 - 只是在執行該方法時,它會獲得一個額外的參數,該參數指向調用它的 object。 這個參數是 static 和非靜態方法之間唯一的 memory 開銷。

暫無
暫無

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

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