child class 是否在内部调用 parent 方法的 super?
Does child class internally call super of parent method?
我对方法覆盖有一点疑问。
Animal animal = new Dog();
animal.makeSound();
狗是动物的childclass。 animal.makeSound()
会调用 dog object makeSound()
因为它是后期绑定。当我们不覆盖 dog
时,它将调用动物 class makeSound()
。但是让我们看看这段代码。
Dog dog = new Dog();
dog.makeSound();
如果狗不覆盖parent方法,它仍然有parent方法,这在继承的情况下是正常的。我只是想知道内部实现。 dog是不是在内部重写了parent方法,在里面像这样调用super?
@Override
public void makeSound() {
super.makeSound();
}
谢谢。
没有。您可以使用 javap
(显示字节码的反编译器工具)来检查这一点。狗class根本就没有makeSound
方法
编译器看到字符“dog.makeSound()”并知道 Animal.class 和 Dog.class 是什么样子——因为它们在 class 路径上,或者那些在同一个汇编 运行 中。因此,编译器本身 'resolves' 你的意思。如果缺少 Dog 或 Animal,编译器将出错,告诉您缺少必需的 class,然后收工 - 没有 class 文件,剩下的就没有意义了。
在 class 文件格式中,方法调用 完全规范 。它们的标识基于完全限定的 class 名称 and 方法名称 and 所有参数的确切类型(没有泛型)和 return类型。只有当所有这些都相同时,JVM 才会认为它是相同的方法。就 JVM 而言,java 代码 "foo".toLowerCase()
中的方法被命名为:“java/lang/String::toLowerCase::()Ljava/lang/String;”。一口,幸运的是,我们在 java 中编程,而不是在字节码中。
因此,在 class 级别,您的 "dog.makeSound();"
被编译为类似以下内容的内容:
INVOKEVIRTUAL com.foo.User214534sPackage.Animal :: makeSound :: ()V
和 JVM,当它看到这个时,检查堆栈顶部的内容(因为这是一个实例方法,'receiver'(dog.
部分)实际上是第一个参数),检查actual 类型是变量指向的对象的类型,计算出它是 com.foo.User214534sPackage.domestics.Dog
,并检查所说的 class 是否有 makeSound
方法定义。如果是,JVM 将实际调用它(即使 INVOKEVIRTUAL 调用仅提及 Animal.makeSound)。如果没有,它将检查 Dog 的父类型.. 并将继续这样做,直到它到达 Animal,它当然有一个 makeSound 方法(如果没有,javac
就无法产生class 文件)。
我对方法覆盖有一点疑问。
Animal animal = new Dog();
animal.makeSound();
狗是动物的childclass。 animal.makeSound()
会调用 dog object makeSound()
因为它是后期绑定。当我们不覆盖 dog
时,它将调用动物 class makeSound()
。但是让我们看看这段代码。
Dog dog = new Dog();
dog.makeSound();
如果狗不覆盖parent方法,它仍然有parent方法,这在继承的情况下是正常的。我只是想知道内部实现。 dog是不是在内部重写了parent方法,在里面像这样调用super?
@Override
public void makeSound() {
super.makeSound();
}
谢谢。
没有。您可以使用 javap
(显示字节码的反编译器工具)来检查这一点。狗class根本就没有makeSound
方法
编译器看到字符“dog.makeSound()”并知道 Animal.class 和 Dog.class 是什么样子——因为它们在 class 路径上,或者那些在同一个汇编 运行 中。因此,编译器本身 'resolves' 你的意思。如果缺少 Dog 或 Animal,编译器将出错,告诉您缺少必需的 class,然后收工 - 没有 class 文件,剩下的就没有意义了。
在 class 文件格式中,方法调用 完全规范 。它们的标识基于完全限定的 class 名称 and 方法名称 and 所有参数的确切类型(没有泛型)和 return类型。只有当所有这些都相同时,JVM 才会认为它是相同的方法。就 JVM 而言,java 代码 "foo".toLowerCase()
中的方法被命名为:“java/lang/String::toLowerCase::()Ljava/lang/String;”。一口,幸运的是,我们在 java 中编程,而不是在字节码中。
因此,在 class 级别,您的 "dog.makeSound();"
被编译为类似以下内容的内容:
INVOKEVIRTUAL com.foo.User214534sPackage.Animal :: makeSound :: ()V
和 JVM,当它看到这个时,检查堆栈顶部的内容(因为这是一个实例方法,'receiver'(dog.
部分)实际上是第一个参数),检查actual 类型是变量指向的对象的类型,计算出它是 com.foo.User214534sPackage.domestics.Dog
,并检查所说的 class 是否有 makeSound
方法定义。如果是,JVM 将实际调用它(即使 INVOKEVIRTUAL 调用仅提及 Animal.makeSound)。如果没有,它将检查 Dog 的父类型.. 并将继续这样做,直到它到达 Animal,它当然有一个 makeSound 方法(如果没有,javac
就无法产生class 文件)。