3

是否可以在 Java 中调用可覆盖的方法,使其始终执行“本地定义”版本而不是子类的覆盖版本?即有没有一个类比super是指这个类,而不是超类?

让我举一个代码示例,希望能清楚地说明我要做什么:

class A {
    void foo() {
        System.out.println("Foo from A");
    }

    void bar() {
        foo();  // <-- This is the important line!
    }
}

class B extends A {
    @Override
    void foo() {
        System.out.println("Foo from B");
    }
}

如果我这样做new B().bar()了,它将调用中bar()定义的方法A,该方法调用foo()被覆盖B以打印“Foo from B”。

有没有一种方法可以强制bar()方法调用foo()中定义的方法,A而不是B?就像我可以使用super.foo()inB调用foo()定义的方法一样A?不幸的是 usingthis.foo()仍然调用子类的版本。即使是类似((A) this).foo()A.this.foo()不起作用的东西。

foo()显然,我可以简单地定义in的私有或最终版本A并调用它。但我希望有一个解决方案,我所做的只是将上面代码示例中的“重要行”更改为调用 foo() 以使其打印“Foo from A”的不同方式,最好不要使用反射之类的技巧。

4

8 回答 8

1

你的对象一个B. 它不是一个A!这是一个例子:

public class Apple {
    public void printColor() {
        System.out.println("I am red");
    }

    public void bar() {
       printColor();
    }
}

然后是子类:

public class GrannySmithApple extends Apple {
    public void printColor() {
        System.out.println("I am green");
    }
}

GrannySmithApples总是绿色的(除非它们已经烂了,但那是另一罐香蕉)!一旦你有了 a GrannySmithApple,它就不再是 aApple了,除非你可以用它做所有相同的事情,你可以用它来做常规Apple( printColor,eat等) 有意义吗?Apple在从常规转换到转换之间没有改变的任何东西GrannySmithApple显然仍然是一样的。

于 2012-11-15T17:45:51.710 回答
1

foo()您可以在 A 中有一个被调用的“内部” 。

class A {
    private void fooInternal() {
        System.out.println("Foo from A");
    }

    void foo() {
        fooInternal();
    }

    void bar() {
        fooInternal();
    }
}

class B extends A {
    @Override
    void foo() {
        System.out.println("Foo from B");
    }
}

new B().bar()现在将打印“来自 A 的 Foo”,而new B().foo()将打印“来自 B 的 Foo”。

于 2012-11-15T18:02:14.167 回答
0

foo()总是调用new ...语句中使用的类的实例方法。

简而言之,我认为您的问题的答案是否定的,这是不可能的。它会阻止你完全覆盖部分行为。

class A {

method1() {
...
method2();
...
}

class B extends A {

// You can override method2 here to change the behaviour of method1 
// because it will call **your** version of method2
// You **don't** have to override method1 to achieve that

method2() {
...
}

}
于 2012-11-15T17:36:42.840 回答
0

据我所知,一个B对象总是会调用它自己的foo()方法。话虽如此,B.foo()可以定义为调用超类的foo()方法。例如,您可以定义B如下:

class B extends A {
    @Override public void foo() {
        super.foo();
    }
}

这样做会有B来自foo. A但是这样做会一直这样做。

于 2012-11-15T17:39:09.287 回答
0

有这个经验法则:

In Inheritance the most specific version of the method for that class is called.

-所以它总是会被调用的foo()方法,如果它在B 的实例上调用。Class B

-如果您希望使用上述代码调用foo()方法,那么您将需要关键字。Class Asuper

例如:

class B extends A {
    @Override
    void foo() {

       super.foo();
    }
}
于 2012-11-15T17:43:44.130 回答
0

this引用“这个对象”,而不是“这个类”。

这意味着如果您有一个B扩展的对象A,当它执行A提到的超类中的方法时this,它实际上将指向 的实例B,因此将在 上执行该方法B

您可以将 in 中的方法A视为默认方法。如果该方法在您的实际对象中被覆盖B,那么它将始终被调用。

我建议你改变你的设计并使用组合而不是继承:这将确保清晰的关注点分离,并使你的代码更容易理解和测试。

于 2012-11-15T17:47:05.980 回答
0

正如其他人所说,没有直接的方法可以做到这一点,但您可以考虑这种构造的变体:

  void bar() {
    ClassA self = new ClassA();
    self.foo();  // <-- This is the important line!
  }
于 2012-11-15T17:51:59.587 回答
0

要么让你的方法静态(baadddddd),要么改变你的设计。

事实上,为子类提供默认行为是没有意义的,因为它被定义为使自己适应相关的方法。

由于您的foo()方法似乎有所不同,您可以实现这样的策略模式:

interface BarProcess{
    void foo();
}

public class DefaultBarProcess implements BarProcess{
    void foo() {
       System.out.println("Foo from A");
    }
}

public class AnotherBarProcess implements BarProcess{
    void foo() {
       System.out.println("Foo from B");
    }
}

class A {

    private BarProcess barProcess;

    public A(Bar barProcess){
      this.barProcess = barProcess;
    }

    void bar() {
        barProcess.foo();
    }
}

class B extends A {  //deprecated! No need to exist

}
于 2012-11-15T17:55:22.063 回答