2

以下代码在运行时显然会打印出“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();
    }
}
4

6 回答 6

5

我不这么认为;如果您method1()在子类中覆盖,则不会。如果您确实需要该行为,则必须声明A.method1()final,并且无法在 中定义它B

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

于 2009-04-24T04:47:17.657 回答
1

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

于 2009-04-24T05:26:23.040 回答
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。当然这是不健康的:注意在 method1 上必要的省略 @Override - 如果你把它放回去,你会得到一个编译器错误:

method does not override or implement a method from a supertype
于 2009-04-24T06:04:48.110 回答
1

为此,您必须使用非虚拟方法 method1。为此,您将其设为最终版本:

  public final void method1() {....

或者您将其设为私有;在 Java 中 pivate 方法总是非虚拟的:

   private void method1() {....

(请注意,在 C++ 中,私有方法可能是虚拟的或非虚拟的;除此之外,这使得在 C++ 中实现模板方法模式更加清晰。)

这是发生了什么:当通过对象引用调用非静态方法时(这是Java中调用非静态对象方法的唯一方法),调用的方法取决于所引用对象的实际类型(指向-to),而不是引用的类型。

在对象方法中,对该对象的其他方法(或成员)的调用隐含地以“this.”为前缀。因此,您在 method2 中对 method1 的调用实际上是:

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

并且this是一个对象引用。在类 A 中的方法 2 中,引用的类型是 A,就好像this已经声明过一样:

A this;

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

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

因此,当 A.method2() 调用 method1() 时,真正发生的是我们this.method1()使用相同的 调用this,它指的是 a BB您在其中实例化main()并调用 method2()。

由于 method1()虚拟的,并且由于我们在对 type 对象的引用上调用 method1() B,因此编译器会确保B对 method1() 的重新定义是被调用的。

于 2009-04-24T06:10:45.880 回答
0

您不能使用标准的“自然”和广为接受的 Java 机制。Java 的设计使得所有方法都是动态分派的,除非是最终的或静态的(或调用超级),并且在您的情况下。由于该方法在 B 中被覆盖,因此这些都不是一个选项。在特定情况下没有“禁用”动态调度的机制,但好消息是很少需要这样做。

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

于 2009-04-24T14:25:28.423 回答
0

Even I WAS looking for this solution. It seems its not possible. Changing the base class is not an option. i.e. assuming that base class is already written and you are deriving a class from it, there's nothing you can do in the derived class so that the base class calls its own methods and not overridden methods. if you are making an object of the derived class, base class will call overridden methods of derived class instead of calling its own methods. that's OOPS....

于 2011-09-22T19:19:37.100 回答