【问题标题】:Overriding and weaking access modifiers覆盖和弱化访问修饰符
【发布时间】:2015-01-31 07:38:26
【问题描述】:

根据JLS 8.4.8.1

在类 C 中声明的实例方法 m1 覆盖另一个实例 方法 m2,在 A 类中声明,当且仅当满足以下所有条件时:

  • C 是 A 的子类。

  • m1 的签名是 m2 签名的子签名(第 8.4.2 节)。

  • 要么:

    • m2 是公共的、受保护的或声明为具有默认访问权限的同一 打包为 C,或

    • m1 覆盖方法 m3(m3 与 m1 不同,m3 与 m2 不同), 这样 m3 会覆盖 m2。

这似乎与以下代码不矛盾:

public class Main {

    public void f() { }
    public static class A extends Main {
        protected void f() { }
    }

    public static void main(String[] args) {

    }
}

DEMO

但它没有编译,即使方法 f() 的覆盖版本具有 protected 访问修饰符,正如我提供的规则的第二点所述。怎么了?

【问题讨论】:

    标签: java overriding jls


    【解决方案1】:

    在 JLS 的下方8.4.8.3 中提供了这样做的理由:

    覆盖或隐藏方法的访问修饰符(第 6.6 节)必须提供至少与覆盖或隐藏方法一样多的访问权限,如下所示:

    • 如果被覆盖或隐藏的方法是公共的,那么覆盖或隐藏的方法必须是公共的;否则,会发生编译时错误。

    • 如果覆盖或隐藏的方法是受保护的,那么覆盖或隐藏的方法必须是受保护的或公开的;否则,会发生编译时错误。

    • 如果被覆盖或隐藏的方法具有默认(包)访问权限,则覆盖或隐藏方法不能是私有的;否则,会发生编译时错误。

    请注意,您在问题中引用的部分实质上是“基类中方法的访问修饰符不能是私有的”,并且根本与覆盖方法的访问修饰符无关。

    【讨论】:

      【解决方案2】:

      您不能覆盖具有更多限制性访问修饰符的方法。方法 f() 是用访问修饰符 public 声明的,但您正试图用更限制性protected 修饰符覆盖它。改变

      public static class A extends Main{
              protected void f(){ }
          }
      

      public static class A extends Main{
              public void f(){ }
          }
      

      【讨论】:

      • 问题是我对正式的JLS 解释很感兴趣。现在我看不出 JLS 是如何阻止这个代码的。
      • 你绝对可以用较弱的访问修饰符覆盖一个方法,假设“较弱”你的意思是“更公开” - 例如,在我刚刚的测试中用公共方法覆盖受保护的方法。很好。你能澄清一下你的意思吗?
      • @JonSkeet 我的意思是更严格的修饰符。
      • 好吧,那样的话我同意。
      猜你喜欢
      • 2012-11-07
      • 2015-11-27
      • 2014-07-31
      • 2016-05-12
      • 2013-03-17
      • 2017-12-19
      • 1970-01-01
      • 2014-11-03
      • 2016-01-29
      相关资源
      最近更新 更多