【问题标题】:How does inheritance technical work?继承技术如何工作?
【发布时间】:2011-07-08 00:07:58
【问题描述】:

我即将在我的公司(我是一名实习生)上做一个关于 Java 继承的演讲。 我想我想通了,我也知道如何使用它。但有一件事不太确定。 存储中存储的方法在哪里。对象如何知道方法在哪里?

例如:

我们有这门课。

class Animal {
    private String desc1;
    protected String desc2;

    public void breath() {
    }

    public void eat() {
    }
}

还有这个类:

  class Dog extends Animal() {
        public void bark() {
        }
    }

我们现在创建一个 Dog 类的 Object:

狗狗 = 新狗();

所以现在我的问题是: 类被加载到堆中。所以 Dog 和 Animal 在堆中。 (编辑:错了,类不会加载到堆中,请看下面的答案。)。 所以,假设我们制作dog.bark()。 dog 如何知道 bark 方法在 Heap 中的位置?知道 Dog 类在哪里吗? 接下来我们制作dog.eat(): 那么当狗知道狗在哪里时,狗知道动物在哪里还是狗知道动物在哪里? 知道我的意思是它在堆上有一个地址。 当我覆盖一个方法时会怎样?存储在哪里?

感谢您的帮助。

【问题讨论】:

    标签: java class object storage heap-memory


    【解决方案1】:

    首先,这是依赖于 JVM 的,JLS 或 JVM 规范中没有要求如何解决这些问题,只有 应该解决 .

    dog如何知道bark方法在Heap中的位置?

    通常你有所谓的Virtual Method Table,或简称为v-table。您可以将其视为将方法标识符(例如bark)映射到函数指针的表。也就是说,如果您调用bark,VM 将查看它的v-table 并调用bark 指向的方法。当你扩展一个类并覆盖一个方法时,方法指针只是简单地交换到覆盖函数上。

    dog如何知道bark方法在Heap中的位置?知道 Dog 类在哪里吗?

    方法和类不像实例那样存储在堆上。他们为什么要这样做?

    也许你和我刚开始接触 OO 编程时有同样的误解。我想如果我实例化 10 个Dog,我会得到 10 个树皮方法。这不是真的。当你实例化一个对象时,你“得到”的基本上是它的成员变量和一个this 引用。然后,您可以看到 this 引用作为调用非静态方法时传递的额外参数。

    【讨论】:

    • 非常感谢,这对我帮助很大:)
    【解决方案2】:

    不,类不会加载到堆中(至少不是您认为的 Java 中的堆),而是加载到称为 PermGen 空间的内存部分。

    我无法准确告诉您 Java 是如何存储这些信息的,但我认为它类似于 C++ 的存储方式(vtable),因为它通常是在 JVM 本机代码中完成的。

    【讨论】:

    • 但是到称为 PermGen 空间的内存部分。代码不在 perm gem 中
    【解决方案3】:

    首先,在 java 中创建的任何对象在对象头的某处都有一个类引用。链接“静态”(不被覆盖,JIT 知道是否有任何方法被覆盖但某个子类)方法很容易,它可以被内联或只是对代码所在的某个特定点的调用。

    这要复杂得多,因为优化代码是使用寄存器中保存的值调用的,而 java 规范要求它们在堆栈中。

    调用覆盖方法有几种方式:

    • 动态检查实例并像静态示例中那样分派调用,这是一个比较/分支调用,比
    • 快得多
    • Inline caches
    • 或已经提到的 v-table 调用。 v-tables 是最慢的

    不过,了解处理器如何执行代码以及调用/内联的方法等是一个很大的话题。我想还缺少一些其他的基本概念。

    【讨论】: