[英]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 實際上做了這樣的事情:
foo
聲明的類型。say(String)
的方法。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.