【问题标题】:Inheritance and memory allocation继承和内存分配
【发布时间】:2019-11-11 18:36:17
【问题描述】:

以下代码:

class Parent {
    public void say(){
        System.out.println("Parent");
    }
}

class Child extends Parent{
    public void say(){
        System.out.println("Parent");
    }
}

class Test {
    public static void main(String[] args){

        Parent p = new Child(); // What does the compiler check  
        p.say();
    }
}

以下问题一直困扰着我。

1.编译期间到底发生了什么?编译器如何知道 Parent p = new Child() 是有效代码,因为在编译时没有创建对象?

2。运行时到底发生了什么?内存是如何分配的

3.对父构造函数的隐式调用会创建一个父对象。还创建了一个子对象。它是如何存储的以及 jvm 如何将其用于方法解析。

4.最后,是 JVM 硬编码不覆盖静态方法和变量还是有其他原因。为什么我们不能使用运行时对象实例方法()为什么不使用运行时对象变量

我可以在哪里阅读有关这些主题的更多信息?

谢谢

【问题讨论】:

  • 请对每个问题提出 一个 个真正的问题,而不是 4 个。而且您最好立即删除关于提供链接给您的最后一句话,因为这样的请求在这里是题外话。跨度>
  • 我试图回答你的问题,但最后一个问题太不清楚了。
  • 3 - 调用构造函数创建实例,它只是初始化(部分)实例。 new 创建新实例(父级没有 new 语句)
  • 单独谷歌所有这些问题,你会找到答案。它们也是寻求答案的好问题,继续搜索
  • 感谢您的快速回归。关于你的问题:这真的取决于。当你真的想成为 Java 专家,当你学习计算机科学,或者由于某种原因 编译器构造 对你来说很重要时......然后学习 JLS 或Java 字节码规范绝对值得。但更多的是“非正式”层面。 记住所有细节(如语法规则或字节码操作码)是没有意义的。但尤其是 JLS 做了很多解释 java.

标签: java jvm late-binding method-resolution-order early-binding


【解决方案1】:

究竟是在编译期间发生的?编译器如何知道 Parent p = new Child() 是有效代码,因为在编译时没有创建对象?

嗯,整本书都是关于这个主题的。本质上,编译器解析输入源,并找到该赋值:

Parent p = new Child(); 

现在编译器做了两件事:

  • 它检查它可以找到关于作业两边的类型的内容
  • 因此它发现:左侧需要一个`Parent`类型的对象
  • 它还会查看右侧,以了解该表达式产生的(潜在)结果类型

所以,最后,编译器会看到:“我需要一个 Parent ... 而我得到的是一个 Child。”然后编译器必须检查 Child 的实例是否满足“我需要 Parent”。显然:确实如此。

运行时到底发生了什么?内存是如何分配的

再一次,整本书都是关于这个的。例如,请参阅here

对父构造函数的隐式调用会创建一个父对象。还创建了一个子对象。它是如何存储的,jvm如何使用它来进行方法解析。

JVM“简单地”知道两件事:

  • 在为 Child 对象保留内存时,还需要考虑任何超类字段所需的内存
  • 因此,最终,您只需拥有一个足够大的内存区域,以容纳所有父类的所有字段,直至 Child 类本身

最后:静态方法是固有的,但是是的,Java 中没有它们的多态性。这只是语言的设计点,以及为 Java 定义的语义。它可以以不同的方式完成,但 20 多年前,Java 之父决定像他们那样做。

【讨论】:

    猜你喜欢
    • 2021-12-06
    • 2011-01-18
    • 2010-12-26
    • 2018-06-15
    • 2020-05-25
    • 1970-01-01
    • 1970-01-01
    • 2011-01-23
    • 1970-01-01
    相关资源
    最近更新 更多