在 Java 中重写私有方法

2022-08-31 15:49:57

正如这里简洁地描述的那样,在Java中重写私有方法是无效的,因为父类的私有方法是“自动最终的,并且对派生类隐藏”。我的问题主要是学术性的。

不允许父级的私有方法被“重写”(即,在子类中独立实现,使用相同的签名)如何不违反封装?子类无法访问或继承父级的私有方法,这符合封装原则。它是隐藏的。

那么,为什么要限制子类实现具有相同名称/签名的自己的方法呢?这有没有一个很好的理论基础,或者这只是某种务实的解决方案?其他语言(C++或C#)对此有不同的规则吗?


答案 1

不能重写私有方法,但可以在派生类中引入一个私有方法,而不会出现问题。这编译得很好:

class Base
{
   private void foo()
   {
   }
}

class Child extends Base
{
    private void foo()
    {
    }
}

请注意,如果尝试将批注应用于,则会出现编译时错误。只要将编译器/IDE 设置为在缺少注释时提供警告或错误,一切都应该没问题。诚然,我更喜欢将C#方法作为关键字,但是在Java中这样做显然为时已晚。@OverrideChild.foo()@Overrideoverride

至于 C# 对“重写”私有方法的处理 - 私有方法首先不能是虚拟的,但你当然可以在基类中引入一个与私有方法同名的新私有方法。


答案 2

好吧,允许覆盖私有方法将导致封装泄漏或安全风险。如果我们假设这是可能的,那么我们将得到以下情况:

  1. 假设有一个私有方法,那么一个扩展类可以像这样简单地重写它:boolean hasCredentials()

    boolean hasCredentials() { return true; }
    

    从而打破了安全检查。

  2. 原始类防止这种情况的唯一方法是声明其方法 。但是现在,这是通过封装泄漏实现信息,因为派生类现在无法再创建方法了 - 它将与基类中定义的方法发生冲突。finalhasCredentials

    这很糟糕:假设此方法最初在 中不存在。现在,实现者可以合法地派生一个类,并为其提供一个按预期工作的方法。BaseDerivedhasCredentials

    但现在,原始类的新版本已发布。它的公共接口不会改变(它的不变量也不会改变),所以我们必须期望它不会破坏现有的代码。只有它这样做,因为现在与派生类中的方法存在名称冲突。Base

我认为这个问题源于一个误解:

为什么/not/不允许父级的私有方法被“重写”(即,在子类中独立实现,使用相同的签名)违反了封装

括号内的文本与其前面的文本相反。Java确实允许您“在子类中独立实现[私有方法],具有相同的签名”。不允许这样做将违反封装,正如我上面所解释的那样。

但是,“不允许父级的私有方法被”覆盖“”是不同的,并且是确保封装所必需的。


推荐