11

我们有下一节课:

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?它是父类的对象,哪个孩子保留为字段?

  • 如果是,抽象类的继承如何工作?您不能创建抽象类的实例。
  • 如果不是,覆盖的方法在哪里举行?

我尝试谷歌,但我发现的只是关于如何继承类等的常见信息。

更新:

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

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

6 回答 6

7

子类不维护任何表示其父类的特殊字段。您可能会按照内部类的思路进行思考,这些内部类确实维护了对其外部类的引用。这是一种特殊情况,并不代表超子类之间的关系。

在内部,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 Virtual Machine Specification是一个很好的阅读来源,尤其是第 2.11.8 节

于 2013-03-12T17:09:58.030 回答
3

好的。让我们逐行浏览您的代码。

你的第一个声明,在你的 'foo' 方法中是

super.foo();

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

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

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

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

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

调用完之后super.foo(),是时候转到下一条语句,它输出“Sub”。


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

抽象类

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

在 Java 虚拟机的上下文中

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

当您覆盖一个方法时,您将具有相同方法签名(方法字段的名称、编号和类型)的方法添加到子类定义中。这是 JVM 找到它的方式,也是存储被覆盖方法的地方。

于 2013-03-12T16:49:19.117 回答
3

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

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

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

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

由于Subextends Super,类的定义Sub包括对类定义的引用Super

回答更新的问题:

当我们用 super 调用方法时,你说,我们正在访问 parent 的方法。但是我们如何在没有父对象的情况下调用这个方法呢?

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

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

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

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

于 2013-03-12T16:49:44.857 回答
1

当您编写时,super.foo();您正在调用超类方法。

sub 类的 foo 方法通过在 super 类方法中添加指令来覆盖 Super 的 foo 方法。

于 2013-03-12T16:49:27.687 回答
1

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

试试这个继承

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");
    }
}
于 2013-03-12T16:50:53.950 回答
0

只有一个对象同时是 Sub、Super 和 Object。它具有每个类的所有非静态字段。一个类实际上只需要一份其方法的代码副本,即使是非静态的也是如此。

于 2013-03-12T16:52:29.737 回答