方法覆盖是否总是运行时多态性?

Lem*_*mmy 7 java overriding run-time-polymorphism

运行时多态性是否总是在方法覆盖时发生,还是只有在方法覆盖期间将子类对象分配给超类变量后调用方法才会发生?

class A {
    public void myFunc() {
        System.out.println("Something");
    }
}

class B extends A {
    public void myFunc() {
        System.out.println("Something else");
    }

    public static void main (String args[]) {
        A obj = new B();
        obj.myFunc(); //Is only this call resolved at run time?
     
        A obj2 = new A();
        obj2.myFunc(); //Or is this call too resolved at run time?
   
        B obj3 = new B();
        obj3.myFunc(); //Is this call resolved at compile time?
    }
}
Run Code Online (Sandbox Code Playgroud)

小智 6

在方法覆盖中,方法解析始终由 JVM 基于运行时对象负责。是的,所有这些调用都会在运行时得到解决。

A obj = new B();
obj.myFunc();
Run Code Online (Sandbox Code Playgroud)
  • 这里的引用变量属于 A 类,但对象属于 B 类。因此,将调用 B 类 myFunc 方法

A obj2 = new A();

obj2.myFunc();

  • 这里引用变量属于 A 类,对象也属于 A 类。因此,将调用 A 类 myFunc 方法

B obj3 = new B();

obj3.myFunc();

  • 这里引用变量属于 B 类,对象也属于 B 类,因此,将调用 B 类 myFunc 方法


Boo*_*boo 5

编译器实际上是否能够优化这三个方法调用中的任何一个或全部,并在编译时或将来的某个实现中解析这些调用是无关紧要的:所有三个方法调用都是运行时多态性的示例,也称为动态调度这是对比的所谓的静态多态性,也称为方法重载,是一个具有多个同名但参数类型不同的方法的类。

这是一个小的 Java 程序:

public class Test {


    public void foo(String inputString)
    {
        System.out.println(inputString);
    }


    public static void main(String[] args) {
        Test test = new Test();
        test.foo("a"); # very obvious method invocation
    }

}
Run Code Online (Sandbox Code Playgroud)

人们非常清楚在运行时将调用什么方法。这是反汇编的字节码:

Compiled from "Test.java"
public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public void foo(java.lang.String);
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: aload_1
       4: invokevirtual #3                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       7: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #4                  // class Test
       3: dup
       4: invokespecial #5                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: ldc           #6                  // String a
      11: invokevirtual #7                  // Method foo:(Ljava/lang/String;)V
      14: return
}
Run Code Online (Sandbox Code Playgroud)

指令11是虚拟方法的运行时分派。

但正如我所说,即使在未来的某些编译器实现中,这被优化为不同的调用,那也只是一个实现细节。