强制调用基类方法

时间:2009-04-24 04:41:01

标签: java inheritance polymorphism

运行时的以下代码显然会打印出“B1 / A2 / B2”。现在,是否有可能打印“A1 / A2 / B2”(即A#method2()应该在A上调用method1(),而不是在B上调用?)

注意:我不需要传递多态,这个问题仅仅是出于好奇。

class A {
    public void method1() {
        System.out.println("A1");
    }

    public void method2() {
        method1();
        System.out.println("A2");
    }
}

class B extends A {
    @Override public void method2() {
        super.method2();
        System.out.println("B2");

    }

    @Override public void method1() {
        System.out.println("B1");
    }
}

public class Tmp {
    public static void main(String args[]) {
        B b = new B();
        b.method2();
    }
}

6 个答案:

答案 0 :(得分:5)

我不相信;如果你在子类中覆盖method1(),那就没有了。如果您确实需要这种行为,则必须将A.method1()声明为final,而无法在B中对其进行定义。

这对我来说没有意义 - 如果你认为你需要,你应该重新考虑你的设计!

答案 1 :(得分:1)

您也可以将A.method1设为私有。然后,即使你有B.method1,也会调用A.method1。但我不确定,你应该检查

答案 2 :(得分:1)

是的,你可以做到。 在包 a

中定义A.
package a;
public class A {
    void method1() {
        System.out.println("A1");
    }
    public void method2() {
        method1();
        System.out.println("A2");
    }
}

在包 b 中定义B:

package b;
import a.A;
public class B extends A {
    @Override public void method2() {
        super.method2();
        System.out.println("B2");
    }
    void method1() {
        System.out.println("B1");
    }
}

将测试放在 a 包中并运行它。结果是A1 / A2 / B2。当然这是不健康的:注意方法1上必要的@Override遗漏 - 如果你把它重新放入,你将得到一个编译器错误:

method does not override or implement a method from a supertype

答案 3 :(得分:1)

要做到这一点,你必须使用method1非虚方法。要做到这一点,你要做到最终:

  public final void method1() {....

或者你把它私有化;在Java中,pivate方法总是非虚拟的:

   private void method1() {....

(请注意,在C ++中,私有方法可能是虚拟的或非虚拟的;以及其他使得在C ++中实现模板方法模式更清洁的方法。)

以下是发生的事情:当通过对象引用调用非静态方法时(这是在Java中调用非静态对象方法的唯一方法),调用的方法取决于引用的对象的实际类型到(指向),而不是参考的类型。

在对象方法中,对该对象的其他方法(或成员)的调用隐含地以“this”为前缀。所以你在method2中对method1的调用确实是:

public void method2() {
    this.method1();
    System.out.println("A2");
}

this是一个对象引用。在类A中的method2中,引用的类型为A,就像声明了this一样:

A this;

但该引用指向B类型的对象;它可以做到这一点,因为B派生自,继承,子类,is-a,A

正如我上面提到的,“当通过对象引用调用非静态方法时,调用的方法取决于引用的对象的实际类型,而不是引用的类型。”当您实例化一个B类型的对象并调用method2()时,您传入的thisthis实际上是任何非静态函数的隐藏参数)是this指向B对象。当B.method2()调用super()时,同样的this被传递给A.method2()。

所以当A.method2()调用method1()时,真正发生的是我们用this.method1()调用this,它引用B,{{1}你在B中即时发送并在on。上调用了method2()。

由于method1() 是虚拟的,并且因为我们在对类型为main()的对象的引用上调用method1(),所以编译器会确保B'对method1()的重新定义是一个名为。

答案 4 :(得分:0)

使用标准的“自然”和广为接受的Java机制,你不能。 Java的设计是为了动态调度所有方法,除非是final或static(或调用super),在你的情况下。由于该方法在B中被重写,因此这些都不是一个选项。在特定情况下没有“禁用”动态调度的机制,但好消息是很少需要。

你可以通过反思克服一些这些限制,但这就像用大锤打开一件珍贵的礼物。

答案 5 :(得分:0)

即使我正在寻找这个解决方案。似乎不可能。 不能更改基类。即假设已经编写了基类并且您从中派生了一个类,那么在派生类中您无法做任何事情,以便基类调用自己的方法而不是重写方法。 如果要创建派生类的对象,基类将调用派生类的重写方法,而不是调用自己的方法。那是OOPS ......