理解堆上的静态和非静态方法表示之间的区别

rol*_*luo 4 java static heap-memory permgen

我已经阅读了一些关于这个主题的帖子:

但我对它们所说明的概念感到困惑:

静态方法(实际上是所有方法)以及静态变量都存储在堆的PermGen部分中,因为它们是反射数据的一部分(类相关数据,而不是实例相关).

因此,方法,无论是否static只存储在类中的堆上的一个副本.现在只有一个副本在类中,我解释为所有方法都属于该类,那么为什么Java只能使用实例化的实例调用非静态方法?

为什么我们有非静态方法属于实例的概念,而不是类?

Avi*_*Avi 6

这个故事的另一面需要提及.当你上课时,说Bar:

public class Bar {
   public static void doSomething() { ... }

   public void doSomethingElse() { ... }
}
Run Code Online (Sandbox Code Playgroud)

在堆上签名doSomethingElse不是,doSomethingElse()doSomethingElse(Bar this).相反doSomething,没有参数(因此你不能this从静态方法调用- 没有this调用).

当你有这样的电话时:

Bar bar = new Bar();
bar.doSomethingElse();
Run Code Online (Sandbox Code Playgroud)

它只是一个语法糖:

doSomethingElse(bar); // I neglected here for simplification but the name of the method in the compiled code also includes the name of the class.
Run Code Online (Sandbox Code Playgroud)

定义扩展类时Foo:

public class Foo extends Bar {
    @Override
    public void doSomethingElse() { ... }
}
Run Code Online (Sandbox Code Playgroud)

另一种方法是创建的doSomethingElse(Foo this).接下来就是一个虚拟表(如果你不熟悉这个术语,请阅读它) - 每个类都有一个虚拟表,它将方法签名映射到具体代码.在运行时调用方法时,根据实例的动态类型,在类(而不是实例)虚拟表中搜索正确的实现.

所以完整的例子就是(当然这只是一个简化):

Java语法(语法糖):

Bar b = new Foo();
b.doSomethingElse();
Run Code Online (Sandbox Code Playgroud)

真正发生的事情(简化):

// Step 1: Get the correct overriden method for Foo class from the virtual table
// Step 2: Invoke the method with the instance "b" as the first parameter (the "this" parameter)
Foo.getMethodFromVirtualTable("doSomethingElse").invoke(b);
Run Code Online (Sandbox Code Playgroud)

这当然只是一种简化,但就像它发生的那样.

事实上,当你想到它时,所有方法在内存中都是静态的(这就是它们驻留的原因PermGen).编译器为每个类使用静态虚拟表,以便调用正确的方法.这允许多态性.

  • 感谢上帝,有人真的在读这个问题.对于explenation tho. (2认同)