方法覆盖总是在运行时多态吗?

时间:2018-10-16 10:43:15

标签: java override 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?
     }
}

请帮助!

5 个答案:

答案 0 :(得分:7)

在方法重写中,方法解析始终由JVM基于RUN TIME OBJECT进行维护。 是的,所有这些调用都将在运行时得到解决。

A obj = new B();
obj.myFunc();
  • 这里引用变量属于类A,而对象属于类B。因此,类B的myFunc方法将被调用

A obj2 = new A();

obj2.myFunc();

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

B obj3 = new B();

obj3.myFunc();

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

答案 1 :(得分:4)

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

这是一个小的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
    }

}

人类很清楚在运行时将调用哪种方法。这是反汇编的字节码:

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
}

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

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

答案 2 :(得分:0)

  • 私有,最终和静态成员(方法和变量)使用静态绑定。

  • 对于虚拟方法(在Java中,方法默认为虚拟),绑定是在运行时根据变量所保存的对象完成的。

因此,为回答您的问题,对于以下所有情况,方法解析始终在运行时完成。 (是否将子类的对象分配给超类的变量或该变量所持有的相同类型的对象)

    A obj = new B();
    obj.myFunc();
 
    A obj2 = new A();
    obj2.myFunc();

    B obj3 = new B();
    obj3.myFunc();

答案 3 :(得分:0)

多态性是面向对象编程中的一个原则:无需关心实现即可编写软件逻辑 至少在原则上,要执行的代码的正确实现是(至少在原则上)

您对此示例有疑问:A a = new A(); 但这等效于此A a = MyFactory.get();

也许JVM执行了一些优化final A a = new B();以避免搜索正确的实现?

答案 4 :(得分:0)

通常,多态性的概念与使用一种类型(类/接口)的不同形式有关,这就是为什么子类需要具有与超类型相似的协定的原因。

考虑到您的问题,所有三个语句都将在运行时解决,但只有第一个属于多态。