超类方法需要引用它的另一个(尽管被覆盖)方法

Superclass method needing to refer to its another (although overridden) method

具有以下超类:

public class SuperClass {

    protected Integer a;
    protected Integer b;
    
    public void doSomething() {
        this.a = 10;
    }
    
    public void doEverything() {
        SuperClass.this.doSomething();
        this.b = 20;
    }
    
    public static void main(String[] args) {
        SuperClass instance = new SubClass();
        instance.doEverything();
        System.out.println(instance.a); //should print 10
        System.out.println(instance.b);
    }
}

以及以下子类:

public class SubClass extends SuperClass {

    @Override
    public void doSomething() {
        super.doSomething();
        super.a *= 10;
    }

    public void doEverything() {
        super.doEverything();
        this.b += 5;
    }
}

输出:

100

25

因此,SuperClass.this.doSomething(); 正在访问 SubClassdoSomething,但我需要它来访问 SuperClassdoSomething。在那种情况下,我没有 super 关键字,因为我已经在 super!

  1. 有没有办法引用¹ deep SuperClass.this.doSomething,所以它会为第一个输出值输出 10?

    ¹ 我对 referencing 感兴趣:我们当然可以将 SuperClassdoSomething 提取到辅助私有方法,直接访问。

  2. 如果没有办法,一个超类方法需要访问它的另一个(尽管被覆盖)方法的情况是否意味着我的 OOP 设计不正确?为什么?

答案是不能参考。执行此操作的唯一方法是您已经知道的私有辅助方法方法。

如果你想知道为什么,我想这只是因为它会无缘无故地使语言复杂化;您始终可以通过使用私有辅助方法获得相同的结果。语法 SuperClass.this.doSomething() 已被用于其他用途。这意味着如果 SuperClass 是封闭实例 class,则调用封闭实例上的方法 doSomething

你不能为所欲为。多态性的工作方式是做你所看到的。

这意味着没有通过 SubClass.doSomething() 从 SuperClass.doSomething() 调用 SuperClass.doSomething() 的直接方法,除非您正在使用 SuperClass 的实际实例.

在其他一些语言中,您有权告诉如何处理此问题,例如在 C++ 中使用关键字 virtual,但在 java 中您没有该选项。所有的方法都是动态绑定的,所以你不能那样做。您只能不覆盖或完全阻止它被覆盖。

我假设您是从 C++ 背景来到 Java 的。这些语言在概念和语法上相似,但在实现上却不同。

你也可以在 Java 中实现我认为是你的意图,但结构看起来与 C++ 不同。

在 Java 中,您示例中的构造 SuperClass.thisthis 完全相同,因此 SuperClass.this.doSomething(); 正是 doSomething() 的样子。那么为什么 Java 有结构 SuperClass.this 呢?它的含义与继承无关。它在嵌套 classes.

的上下文中很有用

想象一下这样的结构:

class A {
    class B {
        public void doSomething() {
         // this here refers to an instance of the class B
         System.out.println(this);
         // We need to write is this way,
         // because this hides the this reference to the instance of A.
         // A.this is the instance of A where this is nested
         System.out.println(A.this); 
     }
}

那么你如何确保能够在 class 中有一个子classes 可以覆盖的方法,并且仍然能够调用特定的实现?

嗯,从严格意义上说,你不能。您可以做的是创建一个无法覆盖的 final 方法,并从非最终方法调用它。

class SuperClass {
    public void doSomething() {
        doSuperClassyThing();
    }

    public final void doSuperClassyThing() { // cannot be overridden
        ...
    }
}

您可以在 Template Method Pattern.

中看到类似的方法(目标略有不同)

如果您遇到这种情况,也许您应该重新考虑并考虑 class 结构还 不正确。

尝试实施以下方法之一:

  1. 组合优于继承。
  2. 正在创建一个新的继承级别(中间的 class 引用了 super)。
  3. 与 (2.) 相同,但使用内部 class.
  4. 将需要的方法提取到一个单独的私有方法中,并在适用的地方调用它。

因为 (1.) 不会像其他的那样枯燥,(4.) 留下一种解决方法的感觉,并且 (2.) 需要创建一个新文件并在外部引用 SuperClass;我认为最接近的方法是 (3.),这是唯一以某种方式在 SuperClass 中引用 super 的解决方案(尽管它实际上是在 SuperClass 内部 class):

SuperClass.java:

public abstract class SuperClass {

    protected Integer a;
    protected Integer b;

    public void doSomething() {
        this.a = 10;
    }

    public abstract void doEverything();

    public static class Impl extends SuperClass {

        @Override
        public void doEverything() {
            super.doSomething();
            this.b = 20;
        }
    }

    public static void main(String[] args) {
        SuperClass instance = new SubClass();
        instance.doEverything();
        System.out.println(instance.a); //prints 10
        System.out.println(instance.b);
    }
}

SubClass.java:

public class SubClass extends SuperClass.Impl {

    @Override
    public void doSomething() {
        super.doSomething();
        super.a *= 10;
    }

    @Override
    public void doEverything() {
        super.doEverything();
        this.b += 5;
    }
}