由于编译器基于引用类型而不是实际的对象类型调用方法,为什么调用对象的方法?

时间:2015-09-15 12:33:45

标签: java polymorphism

代码:

public class X
{
    public void methodA() //Base class method
    {
        System.out.println ("hello, I'm methodA of class X");
    } 
}

public class Y extends X
{
    public void methodA() //Derived Class method
    {
        System.out.println ("hello, I'm methodA of class Y");
    }
}

public class Z
{
   public static void main (String args []) {
       X obj1 = new X(); // Reference and object X
       X obj2 = new Y(); // X reference but Y object
       obj1.methodA();
       obj2.methodA();
   }
}

输出:

hello, I'm methodA of class X
hello, I'm methodA of class Y

调用对象类型的方法而不是引用类型。这两条线都不应该是这个吗?

hello, I'm methodA of class X
hello, I'm methodA of class X

3 个答案:

答案 0 :(得分:1)

编译器选择与方法调用最匹配的方法签名(在具有相同名称的所有重载方法中,可用于调用该方法的变量的编译时类型)。

但是,实际执行的方法仅在运行时确定,具体取决于调用该方法的变量引用的实例的运行时类型。这就是覆盖方法的意思。'

您可能会混淆方法重载(在编译时完成)与方法重写(在运行时完成)。

答案 1 :(得分:1)

很明显。当您在子类中再次声明methodA()时。超级methodA()被超越。所以现在每当你调用methodA()时,都会调用子类的methodA()

X obj1 = new Y();
Y obj2 = new Y();
obj1.methodA();
((X)obj2).methodA();

两者都会调用overriden方法。

在java中,无法调用被覆盖的方法。只有在覆盖函数时调用超类的方法才能做到的事情是:

public void methodA() { //Derived Class method
    super.methodA();
    // add other stuff if you want here
}

答案 2 :(得分:1)

Java使用早期绑定',即在编译期间将名称与方法相关联,以及“动态调度”,选择与对象最密切相关的方法实现。在运行时键入。 Java在绑定时使用引用类型,因为在编译期间可能不知道对象的类型。

X obj1 = new X();    // obj1 is bound to X and of type X
if (i == 0) {
     obj1 = new Y(); // obj1 is still bound to X, but now of type Y
}
obj1.methodA();      
// Due to early binding, a compiler error occurs if X doesn't contain methodA
// Due to dynamic dispatch, if it exists, the methodA of obj1's type will be used. Otherwise the closest superclass's methodA will be used.