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() 的正常构造函数调用。是这样吗 ?当涉及到继承时,这只是类加载吗?
我想知道我在这里的想象是否正确。
我猜 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
。