为什么调用将父亲类作为参数的方法而不是调用将子类作为参数的方法?

时间:2019-02-06 11:01:32

标签: java oop inheritance polymorphism dynamic-binding

我有一个名为A的类和一个扩展A的名为B的类。 在玩弄一些了解多态行为的方法时,我遇到了一种奇怪的情况。

public class Main {
    public static void main(String[] args){
        B b = new B();
        A a = b;
        b.f1(a);
    }
}

public class A {
.
.
.
    public void f1(A a){
        if(a instanceof B)
            f1((B)a);
        else
            System.out.println("Nothing");
    }
.
.
.
}

public class B extends A {
.
.
.
    public void f1(B b){
        System.out.println("B::f1(B)");
    }
.
.
.
}

我希望A类中的f1首先被调用(因为a是A类型的),而实际上是这样。然后我期望线f1((B)a);因为a是B的实例,所以被称为。到目前为止,一切都按预期进行。但是,我认为将要调用的下一个方法是B类中的f1(B)。相反,A类中的f1(A)被反复调用,导致堆栈溢出异常。为什么B类中的f1(B)没有被调用? B的一个实例是调用方,参数被强制转换为B类型。

3 个答案:

答案 0 :(得分:4)

f1(A a)是类A的实例方法。它不了解A子类的方法。因此,它无法调用类void f1(B b)的{​​{1}}。因此,B再次执行f1((B)a)

如果要调用void f1(A a),则必须在类f1(B b)的实例变量上调用f1

B

答案 1 :(得分:1)

您的类A不知道类B存在于某处并且具有B.f1(B b)函数。实际上,f1(A a)和f1(B b)是两个不同的函数。您可能想要实现的目标,应该以不同的方式完成:

public class A {
//...
    public void f1(A a) {
         System.out.println("Nothing");
    }
//...
}

public class B {
//...
    public void f1(B a) {
        // this is different function, because of another parameters
    }

    public void f1(A a) {
        if(a instanceof B)
            f1((B)a);
        else
            super.f1(a);
    }
//...
}

答案 2 :(得分:1)

代码必须按如下所示强制转换方法的调用者:

public class A {

    public void f1(A a){
        if(a instanceof B)
            ((B) this).f1(a);
        else
            System.out.println("Nothing");
    }
}

在代码中,您仅强制转换参数。这样做会递归地调用相同类的相同方法。

如果强制转换为调用方,则通知JVM您想在子类上调用该方法,因此可以立即退出该方法。

重要请注意,根据参数在调用方上调用强制类型转换可能会生成类强制类型异常,例如在以下情况下:

    B b = new B();
    A a = new A();
    a.f1(b);

不能确定在B对象上调用了接收B参数的方法f1