Java对象的方法信息存储在哪里?

5

我刚才的同事问了我一个非常有趣的问题,但我无法回答他。

假设我们有以下类:

public class Person {
    String name;

    public Person(String name) {
        this.name = name;
    }

    public void print() {
        System.out.println("xxx");
    }
}

现在,我们正在创建对象:

Person p1 = new Person("a");
Person p2 = new Person("b");
Person p3 = new Person("c");
Person p4 = new Person("d");
Person p5 = new Person("e");
Person p6 = new Person("f");
Person p7 = new Person("g");
Person p8 = new Person("h");

问题是:
我们是否在每个单独的对象中保留有关可用方法的信息?如果我们创建一个新对象p9,JVM会创建只包含字段信息还是也会添加关于方法的信息?
另一个问题:
如果我调用p1.print()会发生什么?p1是否必须要求Person类提供此方法,还是已经保存在p1对象中?

4
@Vallentin 你会建议他搜索哪些关键词? - Kevin Workman
@KevinWorkman 这个问题怎么样? - vallentin
2
@Vallentin,我觉得那个问题非常有趣。请记住,Google经常将StackOverflow的问题作为答案呈现。问题只需要被提出来。然而,在这种情况下,SO上有类似的问题,但重点是它是一个问答网站。 - Eel Lee
4个回答

5
方法的代码并不会为所有实例重复,这完全是不必要的。代码存储在内存中的特殊区域,并由所有实例共享。另一方面,实例变量所需的内存自然归每个实例所有。
至于方法如何调用,对象并不真正需要每次调用方法时都询问类,它有一个指向方法代码的指针,可以直接调用它。
有关JVM内部工作原理的更多信息,请参见此处:http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html

1
那个特殊的内存区域叫做堆,对吧? :-) - William Morrison
2
不是堆。方法区 - Kayaman

2
一般而言,无论有多少对象,代码只需表示一次。面向对象的概念认为对象“具有”方法只是一个抽象概念。因此,实质上,无论您的方法是实例化还是静态的,在幕后它仍然“属于”类。
对于final方法,调用使用静态绑定(基于表达式类型已经预先确定将调用哪个方法)。
对于虚拟方法,会发生更有趣的事情。根据实现方式,要么对象包含“正确方法的地址”(再次强调不是方法本身),要么运行时反映该对象以确定其实际类并在层次结构中查找适当的方法。

2

我不知道 Oracle JVM 是如何实现的,但在一般的面向对象编程系统中,一个对象会有一个指向自己类的隐藏实例变量。所有的实例都指向同一个类对象,并且指向实例方法的指针是类的一部分。


1
JVM非常出色,它不将对象和方法绑定在一起。为了清楚地理解其功能,您需要了解其底层架构。
JVM有一个类加载器系统,其中包括以下资源:
1. 方法区 2. 堆 3. Java栈 4. PC寄存器 5. 本地方法栈
当我们创建一个对象时,类会被加载(延迟加载),并获得所有所需的资源。在方法区中,所有方法都驻留在堆中的对象中,并在所有线程之间共享。JVM将执行程序所需的所有内存分配/组织为几个运行时内存区域。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接