如果將非static
函數複製到具有該方法的每個對象的堆中,那麼爲什麼默認情況下Java static
中的所有方法都不是?爲什麼要以這種方式浪費所有的堆內存?爲什麼不是每種方法都是靜態方法?
一個圖解說明對我理解這一點會更有幫助。
如果將非static
函數複製到具有該方法的每個對象的堆中,那麼爲什麼默認情況下Java static
中的所有方法都不是?爲什麼要以這種方式浪費所有的堆內存?爲什麼不是每種方法都是靜態方法?
一個圖解說明對我理解這一點會更有幫助。
靜態方法無法訪問對象的實例成員變量...沒有狀態,沒有OOP。
因爲如果每個方法都是靜態的,java將不會是面向對象的。
您需要在不同的對象上調用一個方法,因爲它們具有不同的狀態。
至於內存 - 每個靜態調用也會在堆棧上。
非常感謝大家對我們有幫助的回答 – slimshady
你的問題是爲了比較程序和麪向對象編程。 http://en.wikipedia.org/wiki/Procedural_programming#Comparison_with_object-oriented_programming。 OO與程序的主要動機是讓數據結構能夠自己執行操作。
至於內存分配的假設,方法不會複製到每個對象,因爲Java不支持動態類型修改。例如,如果某個對象的類型爲Foo,那麼它將擁有由Foo類型聲明的所有方法。無法將新方法添加到Foo實例,而無需更改類型本身。無論何時在對象上調用某個方法時,都會在後臺將其作爲過程運行。
只要運行這個:
foo.say("Hello, world!");
的Java實際上做這樣的事情: 「你好,世界」
foo
聲明的類型。say(String)
。foo
對象的實例狀態運行該方法。由於方法保持它們自己的狀態,任何非靜態方法都可以通過將對象實例作爲方法參數傳遞來以靜態方式實現。事實上,上面的第4步可能由Java編譯器以這種方式實現。
非靜態方法不會「針對堆中的每個對象進行復制」。每個類加載器只有一個方法(代碼)的副本,與static
方法相同。
制定一個方法static
不是關於內存管理 - 靜態方法需要一些堆棧和堆,就像動態方法一樣。
請參閱Understanding Instance and Class Members Java教程,以獲取有關static
用於的內容的說明。
該方法的代碼不在堆棧中,它在堆的一部分中(永久生成,由垃圾回收器特殊設置)。在堆棧上只有方法的局部變量(和類似的返回地址等類似的運行時數據)被定位。
這與它們是靜態或非靜態方法無關。
此外,該方法的代碼將而不是被複製爲每個對象的類 - 只是執行該方法時,它會獲得一個額外的參數,它指向它被調用的對象。這個單一的參數是靜態和非靜態方法之間唯一的內存開銷。
通常,Java方法是而不是通過將方法複製到每個對象的堆上來實現。相反,方法通常使用稱爲虛擬功能表(或「vtable」)的東西來實現。其思想是,每個方法都有一個副本,無論是靜態方法還是非靜態方法,並且指向這些方法的指針都被放置到表中。然後堆中的每個對象都會存儲一個指向其對象類型的vtable的指針。這意味着任何堆對象的大小都不取決於對象所具有的方法的數量。實際上,具有100個方法的對象與具有1個方法的對象大小相同(假設它們具有相同的字段)。每個只存儲一個指向其對象類型的vtable的指針,其中只有一個副本。
這種優化下原本用來++支持快速虛函數,至今在許多其它面嚮對象語言被使用。它允許對象很小,但支持動態分派。
換句話說,方法不需要缺省被static
,因爲他們不堆中的對象的大小做出貢獻。對於具有更多功能的對象,創建對象不會花費更長時間,或者它會佔用更多的堆空間。
下面是一些對象佈局的可能圖表(ASCII藝術的道歉!)。假設我們有兩個類,A和B.然後在內存中,這些類型的對象可能是這樣的:
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股同虛函數表的兩個對象,以及如何類型A的對象和B僅爲其vtable指針使用相同數量的空間,即使它們具有不同數量的方法。
至於方法去,'static'關鍵字表明,該方法是在類級別,並且不屬於任何特定的實例,並沒有任何內存分配,堆棧或堆內存。 –
這個問題引發了另一個問題 - 您是否閱讀過OOP技術? –
@Hovercraft充滿了鰻魚 - 我認爲這個問題在被問到時措辭不佳。問題不是「爲什麼要有非靜態方法」,而是「看起來非靜態方法使用比靜態方法更多的空間;爲什麼這是默認方法?」 – templatetypedef