当我们在子类中调用超类构造函数时,构造函数调用,

问题描述 投票:0回答:1

超级班

package objectAndClass;

public class Cycle {
    public int speed;
    public int gear;
    public Cycle(int sp, int gr) {
        this.speed = sp;
        this.gear = gr;
        System.out.println(this.hashCode());
        System.out.println(this.getClass().getName());
    }
    public void speedUp(int increment) {
        speed = speed + increment;
    }
    public void applyBrakes(int decrement) {
        speed =- decrement;
    }
    public void changeGear(int gr) {
        gear = gr;
    }

    public String toString() {
        return "Number of gears : "+gear+", And Speed of Bicycle is : "+speed;
    }
}

子类

package inheritance;

import objectAndClass.Cycle;

public class MountainBike extends Cycle {
    public int seatHeight;
    public MountainBike(int speed, int gear, int sh) {
        super(speed, gear);
        System.out.println(this.hashCode());
        System.out.println(this.getClass().getName());
        this.seatHeight = sh;
    }
    public void adjustSeatHeight(int height) {
        seatHeight = height;
    }
    public String toString() {
        return (super.toString()+"\n Seat height is : "+seatHeight);
    }

    public static void main(String[] args) {
        MountainBike mb = new MountainBike(60, 4, 15);
        System.out.println(mb.toString());
    }

}

我曾经应用继承(在子类构造函数中使用 super() ),认为首先创建超类实例,然后创建子类实例。但后来我遇到了几个参考文献,比如继承类的对象创建 - 链接 1继承类的对象创建 - 链接 2

我在这些参考资料中发现有趣的地方,例如:

**创建对象时,必须调用构造函数,但调用构造函数时,则不是强制的,对象创建是强制的。 **

虽然我也参考了 super 的文档,super。从那里我开始知道,如果子类构造函数显式或隐式地调用其超类的构造函数,您可能会认为将调用一整套构造函数,一直回到 Object 的构造函数。

总结参考文献,我认为正在发生的事情是,与正常的构造函数调用不同,即使存在对构造函数链的调用,也不会在继承中专门为超类创建对象。它只是子类的单个实例,处于 IS-A 关系,因此基本上可以访问所有属性和方法。

我猜 JVM 在某种程度上通过不在这里创建超类实例来区分使用 new 关键字和 super() 的正常构造函数调用。是这样吗 ?当涉及到继承时,这只是类加载吗?

我想知道我在这里的想象是否正确。

java oop inheritance instance super
1个回答
0
投票

我猜 JVM 在某种程度上通过不在这里创建超类实例来区分使用

new
关键字和
super()
的正常构造函数调用。是这样吗?

区分这两种形式的不是 JVM,而是编译器。它们的编译方式不同。

在 Java 字节码中,构造函数只是具有特殊名称

<init>
的方法。
invokespecial
指令用于调用构造函数(除其他外)。请注意,该指令要求首先将一个对象(以及构造函数的参数)压入堆栈。就好像构造函数是一个常规的非静态方法,在未初始化的实例上调用。可以将构造函数视为:

someUninitalisedThing.<init>()

另一方面,有

new
指令。这就是创建一个新对象并将其推入堆栈的过程。然后
<init>
将在此对象上调用。

也就是说,

new SomeClass()
被编译为两条指令(使用IntelliJ使用的字节码语法):

NEW SomeClass
INVOKESPECIAL SomeClass.<init> ()V

另一方面,如果您已经在构造函数中,则您已经可以访问未初始化的对象,可以在该对象上调用超类构造函数(或此类的另一个构造函数)。回想一下,就 JVM 而言,构造函数有点像非静态方法,因此我们可以访问

this

因此构造函数中的

super()
将编译为:

ALOAD 0
INVOKESPECIAL SomeSuperclass.<init> ()V

ALOAD 0
加载索引 0 处的局部变量,在本例中存储
this

© www.soinside.com 2019 - 2024. All rights reserved.