如果将非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