這些不同的方法類型在內存中如何處理?內存中的靜態方法和實例方法
我發現了兩個不同的解釋,這樣的:
靜態方法是隻在內存中一次,而實例方法是在內存中多次,每個實例中的每個實例正確處理好membervariables引用。
所有方法在內存中只有一次,實例方法只獲取對象的實例作爲參數。
不同的編譯器使用什麼方式?
這些不同的方法類型在內存中如何處理?內存中的靜態方法和實例方法
我發現了兩個不同的解釋,這樣的:
靜態方法是隻在內存中一次,而實例方法是在內存中多次,每個實例中的每個實例正確處理好membervariables引用。
所有方法在內存中只有一次,實例方法只獲取對象的實例作爲參數。
不同的編譯器使用什麼方式?
約翰內斯說,簡短的答案几乎總是#2。兩者都只存在於單個位置的內存中,但實例方法具有上下文(這基本上是一個額外的隱藏參數),使它們可以訪問該實例。
但是:一些語言/環境會實例化一個看起來像(像一個函數一樣天真的閱讀源代碼)的函數多次。 JavaScript就是一個很好的例子:函數對象在其定義的範圍內關閉,所以如果有多個範圍(比如一個函數被多次調用),就會產生多個不同的函數對象。 (口譯/ JIT-ERS可以優化代碼是否是重複的,但是在概念上它是與函數引用不同。)
下面是在JavaScript的例子:
function foo() {
alert("hi there");
}
function buildBar(x) {
function bar() {
alert(x);
}
return bar;
}
var f1, f2;
f1 = foo;
f2 = foo;
f1();
// alerts "hi there"
f2();
// alerts "hi there"
alert("f1 === f2 ? " + (f1 === f2));
// alerts "true", there is only one `foo`
var b1, b2;
b1 = buildBar("one");
b2 = buildBar("two");
b1();
// alerts "one"
b2();
// alerts "two"
alert("b1 === b2 ? " + (b1 === b2));
// alerts "false", there are two `bar`s
這一點在某些實施方式中相關的JavaScript中的「私人」實例數據,其中人們在構造函數中定義實例方法(很像buildBar
定義bar
),因此他們可以訪問在構造函數中聲明的私有變量。這具有所需的效果(私有實例數據),但影響多個函數實例 - 對於對象的每個實例都有一個實例。
兩者在內存中只有一次。唯一的區別是實例方法獲得另一個第一個參數:類本身的實例。
什麼確實在內存中存在多次(至少對於.NET)是泛型類和它們各自的具體用途。如果您同時使用List<int>
和List<string>
,那麼您最終將得到兩個JITted代碼拷貝,一個針對int
,一個針對string
。
實例方法可以是虛擬的。因此,對於具有虛擬方法的對象的每個運行時實例,運行時環境保持對虛擬方法的引用的管理。但是這些方法只能在內存中存在一次(但是它是運行時環境,它決定了它在內存中加載方法的次數)。
對於非虛擬方法,可以在編譯器時確定引用。
所有編譯器都使用(2) – 2010-02-05 09:05:46
#2方法聽起來比#1更合乎邏輯。 – Dor 2010-02-05 09:06:35
@尼爾,當然是所有?你怎麼能這麼肯定? – 2010-02-05 09:23:43