如何在内存中处理这些不同的方法类型。
我发现了两种不同的解释:
静态方法只在内存中存在一次,而实例方法在内存中多次,每个实例一个,以便在每个实例中正确处理对成员变量的引用。
所有方法在内存中只有一次,而实例方法只将对象的实例作为参数。
不同的编译器使用什么方式?
答案 0 :(得分:2)
正如约翰内斯所说,简短的答案几乎总是#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
),因此他们可以访问声明的私有变量在构造函数中。这具有所需的效果(私有实例数据),但是多个函数实例的影响 - 对象的每个实例都有一个。
答案 1 :(得分:1)
两者都只在内存中存在一次。唯一的区别是实例方法得到另一个第一个参数:类本身的实例。
在内存中多次存在(至少对于.NET)是泛型类及其各自的特定用途。如果同时使用List<int>
和List<string>
,则最终会得到两个代码的JITted副本,一个针对int
,一个针对string
。
答案 2 :(得分:0)
实例方法可以是虚拟的。因此,对于具有虚方法的对象的每个运行时实例,运行时环境保持对虚方法的引用的管理。但是这些方法只需要在内存中存在一次(但是运行时环境决定了它在内存中加载方法的次数)。
对于非虚方法,可以在编译时确定引用。