覆盖方法是否可以使用与基类中不同的访问说明符?

jam*_*jam 21 java abstract modifiers

在抽象类中,哪个访问修饰符必须用于方法,因此子类可以决定它是否应该是公共的?是否可以"覆盖"Java中的修饰符?

public abstract class A {

    ??? void method();
}

public class B extends A {
    @Override
    public void method(){
        // TODO
    }
}

public class C extends B {
    @Override
    private void method(){
        // TODO
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道静态绑定会有问题,如果有人打电话:

// Will work
A foo = new B()
foo.method();

// Compiler ?
A foo = new C();
foo.method();
Run Code Online (Sandbox Code Playgroud)

但也许还有另一种方式.我怎么能做到这一点?

Jir*_*sek 12

可以放宽限制,但不要限制它:

public abstract class A {
    protected void method();
}

public class B extends A {
    @Override
    public void method(){    // OK
    }
}

public class C extends A {
    @Override
    private void method(){    // not allowed
    }
}
Run Code Online (Sandbox Code Playgroud)

使原始方法private也不起作用,因为这种方法在子类中不可见,因此无法覆盖.

我建议使用interfaces来有选择地公开或隐藏方法:

public interface WithMethod {
    // other methods
    void method();
}

public interface WithoutMethod {
    // other methods
    // no 'method()'
}

public abstract class A {
    protected void method();
}

public class B extends A implements WithMethod {
    @Override
    public void method(){
      //TODO
    }
}

public class C extends B implements WithoutMethod {
    // no 'method()'
}
Run Code Online (Sandbox Code Playgroud)

...然后只通过接口处理实例.

  • 嗯......一个有趣的想法,但是......这样你就可以让`WithMethod`扩展`WithoutMethod`.然后类`C`将隐式实现`WithoutMethod`.然而,正如"B"类一样,这可能是也可能不是OP首先想要的. (2认同)

Kon*_*kov 8

覆盖方法时,只能将修改器更改为更宽的方法,反之亦然.例如,此代码有效:

public abstract class A {

    protected void method();
}

public class B extends A {
    @Override
    public void method() { }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果您尝试缩小可见性范围,则会出现编译时错误:

public abstract class A {
    protected void method();
}

public class B extends A {
    @Override
    private void method() {}
}
Run Code Online (Sandbox Code Playgroud)

对于你的情况,我建议C不要实现A,因为A抽象暗示有非私有method():

public class C {
    private void method(){
      //TODO
    }
}
Run Code Online (Sandbox Code Playgroud)

另一种选择是method()在C抛出RuntimeException时实现:

public class C extends A {

    @Override
    public void method(){
        throw new UnsupportedOperationException("C doesn't support callbacks to method()");
    }
}
Run Code Online (Sandbox Code Playgroud)


Gho*_*ica 7

出于很好的理由,你所要求的是不可能的.

在里氏替换原则基本上是说:一个S类是另一个类T的子类只有到那时,当你可以用一些"S对象"取代一些"T对象"的任何发生-没有注意到.

如果你允许S将公共方法简化为私有,那么你就不能再那样做了.因为突然之间,在使用某些T ...时可以调用的方法在S上不再可用.

长话短说:继承不是简单地从天而降的东西.它是类,属性,你作为程序员负责.换句话说:继承不仅仅意味着在源代码中写下"class S extends T"!