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

jus*_*ame 36 java access-modifiers

在我的抽象课中,我有这样的事情:

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

protected abstract void methodIDontWantExposed();
Run Code Online (Sandbox Code Playgroud)

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

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

Jon*_*eet 37

不可以.子类总是可以使方法更公开.

即使他们不能用你班上的方法做到这一点,他们也可以写:

public void callsMethodIDontWantExposed() {
    methodIDontWantExposed();
}
Run Code Online (Sandbox Code Playgroud)

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

  • 我建议你可能只想要文档那样的效果. (11认同)
  • @justsomeusername 在我看来,你好像在试图防止其他人犯下粗心或无知的错误。根据我的经验,重写方法是为了引入多态性变化,我什至很少考虑增加可见性。在这种情况下,我看不出文档有什么好处。您是否真的想浪费精力用以下内容记录一半受保护的方法:“_如果您覆盖此内容,请不要将其公开,除非您需要公开它。_”?你付出多少努力都无法保证人们在使用/继承你的类时不会犯错误。 (2认同)
  • 有趣的是注意到Java和C#之间存在差异:在C#中,采用一种不公开的类型参数或返回这种类型的参数的方法不能公开; Java没有这样的限制,甚至允许从外部代码调用这些方法. (2认同)

aio*_*obe 34

不,在重写方法时,子类总是可以扩大访问范围.没有办法阻止这一点.但是,通常,当我覆盖方法时,我很少将可见性从受保护更改为公共.仔细记录方法的目的可能足以说服实施者在这种情况下这是一个坏主意.

如果您真的想以私有方式封装行为,可以按以下方式执行操作:

abstract class YourClass {
    private HandlerInterface unexposedHandler;

    YourClass(HandlerInterface handler) {
        unexposedHandler = handler;
    }

    public Object methodIWantToExpose(){
        // ... 
        handler.methodIDontWantExposed();
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

使用Java 8,您甚至可以创建HandlerInterface一个功能界面并方便地使用lambda,如下所示:

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

    ...
}
Run Code Online (Sandbox Code Playgroud)


Era*_*ran 6

这取决于您是否希望您的类的用户能够覆盖该方法.如果让它们覆盖它,它们总是可以使用公共方法覆盖它.

有些方法可以避免让它们覆盖该方法:

  1. 它是在抽象类中实现并使其成为final,因此无法覆盖它.

  2. 使其包为私有,并在属于同一个包的一个或多个子类中实现它.由于您是实现它的人,您可以将其保密,或将其更改为最终保护,以便您的包外的子类无法使用公共方法覆盖它.


biz*_*lop 6

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

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

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

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();
      // ...
   } 
}
Run Code Online (Sandbox Code Playgroud)


ant*_*nio 5

您不能因为增加方法的可见性不会破坏基类合同.

看看为什么Java允许增加子类中受保护方法的可见性?