继承和内存分配

时间:2019-07-01 04:27:43

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

对于以下代码:

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进行了硬编码,以使其不能够覆盖静态方法和变量,或者还有其他原因。为什么我们不能使用运行时对象实例method()为什么不使用运行时对象变量

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

谢谢

1 个答案:

答案 0 :(得分:2)

  

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

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

Parent p = new Child(); 

现在,编译器执行两件事:

  • 它检查在分配双方都能找到的有关类型的信息
  • 因此发现:左侧需要一个类型为'Parent'的对象
  • 它也位于右侧,以了解该表达式产生的(潜在)结果类型

因此,最后,编译器将看到:“我需要一个父级...并且我得到的是子级。”然后,编译器必须检查Child的实例是否满足“我需要父母”。显然:是的。

  

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

同样,整本书都写了。例如,请参见here

  

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

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

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

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