当有人覆盖它们时,我可以强制保护抽象方法吗?

Can I force abstract methods to be protected when someone overrides them?

在我的摘要 class 中,我有这样的内容:

public Object methodIWantToExpose(){
  // ... 
  methodIDontWantExposed()
  // ...
}

protected abstract void methodIDontWantExposed();

问题是,我想强制扩展 methodIDontWantExposed() 的人使其受到保护,因为我不希望扩展 class 同时暴露 methodIDontWantExposed 和 methodIWantToExpose。

有没有办法做到这一点(或可以避免我的问题的不同方法)?

没有。一个 subclass 可以 always 使方法更 public.

即使他们不能用您 class 中的方法做到这一点,他们也总是可以写:

public void callsMethodIDontWantExposed() {
    methodIDontWantExposed();
}

...所以你也会遇到同样的情况。

不,你不能。如果它是一个具体的方法,您可以将其设为私有。在你的情况下,没有聪明的方法来阻止扩展 class 声明它 public (你当然可以评论该方法,说它不应该 public)。

不,子类在覆盖方法时总是可以扩大访问范围。没有办法阻止这种情况。然而,通常,当我覆盖一个方法时,我很少将可见性从受保护更改为 public。仔细记录该方法的目的可能足以让实施者相信在这种情况下这不是一个好主意。

如果你真的想以私有方式封装行为,你可以按照以下几行做一些事情:

abstract class YourClass {
    private HandlerInterface unexposedHandler;

    YourClass(HandlerInterface handler) {
        unexposedHandler = handler;
    }

    public Object methodIWantToExpose(){
        // ... 
        handler.methodIDontWantExposed();
        // ...
    }
}

使用 Java 8,您甚至可以使 HandlerInterface 成为函数式接口并方便地使用 lambda,如下所示:

class YourSubClass extends YourClass {
    YourSubClass() {
        super(() -> {
            System.out.println("This is the unexposed code");
        });
    }

    ...
}

这取决于您是否希望 class 的用户能够覆盖该方法。如果你让他们覆盖它,他们总是可以用 public 方法覆盖它。

一些方法可以避免让他们覆盖该方法:

  1. 在摘要中实现它 class 并使它成为最终的,所以它不能被覆盖。

  2. 将它设为私有并在属于同一包的多个子class之一中实现它。由于您是实施它的人,您可以将其包私有,或将其更改为最终受保护,这样包外的子 classes 将无法使用 public方法。

你不能,因为增加方法的可见性不会破坏基础 class 契约。

看看Why Java allows increasing the visibility of protected methods in child class?

在某些情况下,您可以完全避免使用抽象方法(甚至子类化),而是可以使用在枚举中定义的 strategy

当然,使用的枚举实例仍然可以公开,但至少可以保证唯一允许的行为是您的枚举中定义的行为。

所以你的解决方案应该是这样的:

enum Behaviour {
  ONE() {
     public Object doSomething() { return "ONE"; }
  };

   public abstract Object doSomething();
}

// and your class

public abstract class MyClass {
   private final Behaviour behaviour;

   protected MyClass( Behaviour behaviour ) {
     this.behaviour = behaviour;
   }

   public final void methodIWantToExpose() {
      // ...
      behaviour.doSomething();
      // ...
   } 
}