super() 是否在编译时运行,this() 在运行时运行?为什么?

Does super() run in compiletime and this() run in runtime? and why?

提问人:ahmed alaa 提问时间:12/17/2022 更新时间:12/17/2022 访问量:82

问:

在这个程序中,它将打印“学生 1 人 1 本科生 2 ”

这意味着 Student 的 super.method1() > super() this.method2() 本科生的这个

super() 是否在编译时运行,this() 在运行时运行?为什么 ?

public class Person {
    public void method1() {
        System.out.print("Person 1 ");
    }
    public void method2()  {
        System.out.print("Person 2 ");
    }
}
public class Student extends Person {
    public void method1() {
        System.out.print("Student 1 ");
        super.method1();
        this.method2();
    }
    public void method2() {
        System.out.print("Student 2 ");
    }
}
public class Undergrad extends Student {
     /*public void method1() {
         System.out.print("ahmed");
     }*/
     public void method2() {
         System.out.print("Undergrad 2 ");
     }
}
public class main {
    
    static void main(){
        Person u = new Undergrad();
        u.method1();    
        
    }

}

我期望输出:它会导致无限执行,一遍又一遍地打印“学生 1”。

输出为:“学生 1 人 1 本科生 2”。

java oop 这个 超类

评论

0赞 ahmed alaa 12/17/2022
/*你期望的输出是什么*/ public class Student extends Person { public void method1() { System.out.print(“Student 1 ”);super.method2();this.method2();} public void method2() { System.out.print(“学生 2 ”);

答:

1赞 Sweeper 12/17/2022 #1

你是对的,因为 vs 有某种“编译时与运行时”的区别,但肯定不是在编译时“运行”。super.xxx()this.xxx()super.xxx()

更准确的措辞是,调用将调用的方法在编译时决定(静态调度)。调用将调用的方法在运行时决定(动态调度)。super.xxxthis.xxx

您可以通过比较 Java 语言规范中有关处理方法调用的部分中的子句来了解这一点。和 之间不同的重要步骤是(强调我的):super.xxxthis.xxx

编译时步骤 1:确定要搜索的类型

如果形式是 ,则设 T 为主表达式的类型。如果 T 是类或接口类型,则要搜索的类型为 T,如果 T 是类型变量,则搜索的类型为 T 的上限。Primary . [TypeArguments] Identifier

如果形式是 ,则要搜索的类型是其声明包含方法调用的类的直接超类类型。super . [TypeArguments] Identifier

请注意,这是在编译时完成的。调用将导致搜索,因为是“其声明包含方法调用的类”。最终,我们将在后面的步骤中找到。super.method1();StudentPersonPersonPerson.method1

另一方面,呼入将搜索 .this.method2();StudentStudent

找到要调用的方法

  • 设为方法调用的限定类或接口 (§13.1)。Q

  • 假设是 Q 中的方法或 Q 的超类或超接口(请注意,m 只是前面方法的名称 部分;这是实际的声明。m

  • 设为声明 m 的类或接口。C

[...]

  • 如果调用模式为 super,则不允许覆盖。类或接口 C 的方法 m 是要调用的方法。如果 m 是抽象的, 抛出 AbstractMethodError。

[...]

  • 否则,调用模式为 或 。interfacevirtual

    如果类或接口 C 的方法 m 是私有的,则它是要调用的方法。

    否则,可能会发生覆盖。下面指定的动态方法查找用于查找要调用的方法。查找 过程从类 R(目标的实际运行时类)开始 对象。

这是一个运行时步骤。对于 ,是(因为我们找到了 ),而调用模式是 ,所以这就是调用的内容。super.method1();CPersonPerson.method1()super

对于 ,将进行动态方法查找,在本例中,这涉及根据 的运行时类型查找适当的被覆盖方法。this.method2();this