Java中的inheritance如何工作?

我们有下一课:

class Super { void foo() { System.out.println("Super"); } } class Sub extends Super { void foo() { super.foo(); System.out.println("Sub"); } } public class Clazz { public static void main(String[] args) { new Sub().foo(); } } 

输出是:

问题:

super礼物是什么? 它是父类的对象,哪个孩子保持为字段?

  • 如果是,抽象类的inheritance如何工作? 您无法创建抽象类的实例。
  • 如果不是,那么被覆盖的方法在哪里举行?

我试过谷歌,但我找到的只是关于如何inheritance类等的常见信息。

更新:

你还在告诉我显而易见的事情。 也许我的问题有点误导,但我会试着改写它:

  • 当我们用super调用方法时,你说,我们正在访问父方法。 但是如何在没有父对象的情况下调用此方法呢?
  • 这个super一样吗? 如您所知, this是对具体对象的引用。

子类不维护任何表示其父级的特殊字段。 您可能正在思考内部类的某些内容,这些内部类确实维护对其外部类的引用。 这是一种特殊情况,并不代表超级子类如何相互关联。

在内部,JVM维护一个’方法表’,将其加载的每个类与该类可用的方法相关联。 JVM还知道它加载的所有类之间的关系,包括超子关系。

当您调用super函数时,JVM实际上会执行以下操作:

  • 确定要从中调用方法的类的父级
  • 确定将被调用的父级的方法
  • 使用特殊指令调用该方法( invokespecial

如果您要检查Sub类的类文件,您会看到foo方法的类似内容:

 void foo(); flags: Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #2 // Method Super.foo:()V 4: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 7: ldc #4 // String Sub 9: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 

清单中的第1行显示了调用超类方法的特殊指令。

读取的一个很好的来源是Java虚拟机规范 ,特别是第2.11.8节 。

好的。 我们一行一步地通过您的代码。

你的’foo’方法中的第一个陈述是

 super.foo(); 

那是对超类foo方法的显式调用。 这是:

  void foo() { System.out.println("Super"); } 

所以“Super”输出到控制台,因为你已经用super关键字明确地调用了这个方法。 super指的是类的超类,与引用当前类的方式相同。

接下来是子类中foo方法的其余部分:

  void foo() { super.foo(); System.out.println("Sub"); } 

super.foo()之后,是时候转到下一个语句,输出“Sub”。


你的程序首先移动到子类’方法而不是超类的原因是因为一个叫做Polymorphism的原理。 也就是说,子类从超类中获取方法,并改变它的行为。

抽象类

您不能创建Abstract类的实例,不能,但是使用super关键字,您仍然可以访问超类的function。

在Java虚拟机的上下文中

那么当你进行方法调用时,如果它是一个实例方法,那么Java虚拟机将在本地类中查找该方法。 如果找不到它,它将移动到超类。 当您使用Polymorphism原理时,JVM会在子类中找到具有正确签名的方法,并停止查找。 这就是inheritance和Polymorphism在Java的上下文中以简单的术语工作的方式。

覆盖方法时,可以向子类定义添加具有相同方法签名(方法字段的名称,编号和类型)的方法。 这就是JVM找到它的方式,这是存储重写方法的地方。

super是一个关键字,允许您调用超类中定义的方法实现。 它不是您的子类的字段。

如果不是,那么覆盖的方法在哪里举行?

我不太清楚你的意思,但是:

  • 打印“超级”的方法保存在超类的类定义中
  • 打印“Sub”的方法保存在子类的类定义中。

由于Sub扩展了SuperSub类的定义包括对Super类定义的引用。

回答更新的问题:

当我们用super调用方法时,你说,我们正在进行父方法。 但是如何在没有父对象的情况下调用此方法呢?

方法只是一个代码块,只是我们需要执行的一系列字节码指令。 当您调用方法时,JVM的任务是根据您提供的方法名称和参数确定在哪里找到此代码块。 通常,正如其他人所说,它将首先查看调用该方法的对象的类的类定义。 当你使用super ,你告诉JVM不要在这里查看,而是查看父类定义。

因此,您不需要单独的SuperSub实例,因为Sub SuperSuper new Sub() instanceof Supertrue ),并且因为JVM知道super关键字意味着它应该查找构成方法的代码在Super的类定义中。

这个超级一样吗? 如您所知,这是对具体对象的引用。

不,他们不一样。 this是对当前对象的引用,而super不是对对象的引用,而是一个关键字,它影响JVM查找定义正在调用的方法的代码的位置。

当你写super.foo(); 你正在调用超类方法。

class sub的foo方法通过向超类方法添加指令来覆盖Super的foo方法。

子类.super.foo()中的foo方法覆盖调用print super,然后调用System.out.println(“Sub”); 显示Sub。

试着inheritance这个

 class Super { Super() { System.out.println("1"); } void foo() { System.out.println("Super"); } } class Sub extends Super { public Sub() { // TODO Auto-generated constructor stub System.out.println("2"); } void foo() { super.foo(); System.out.println("Sub"); } } 

只有一个对象同时是Sub,Super和Object。 它具有每个类的所有非静态字段。 一个类实际上只需要一个代码副本用于其方法,甚至是非静态代码。