降低静态方法的可见性

时间:2014-11-17 00:41:00

标签: java inheritance information-hiding

我知道孩子不能降低非静态方法的可见性,我理解为什么会这样。

我已经读过了#34;静态方法可以通过重新声明来隐藏"。但是我不明白如何用Java实现这一目标。

这真的有可能吗?如果是,那该怎么做(代码示例)以及它为什么被引入(它似乎与非减少接口可见性的原则相矛盾)?

4 个答案:

答案 0 :(得分:5)

简短的回答是:不,这是不可能的。你混淆了一些术语。 隐藏辅助功能无关(这是您真正要求的,而不是可见性,与范围<相关< / em>和 shadowing ,在Chapter 6 of the Java Language Specification (JLS))中进行了讨论。

现在回答更长的问题。术语覆盖适用于实例方法,而术语隐藏适用于类(static)方法。来自Java Tutorial topic Overriding and Hiding Methods

  

隐藏静态方法和覆盖实例方法之间的区别具有重要意义:

     
      
  • 被调用的重写实例方法的版本是子类中的版本。
  •   
  • 被调用的隐藏静态方法的版本取决于它是从超类还是从子类调用。
  •   

此处的其他一些答案提供了有关方法隐藏的错误示例,因此让我们回到JLS,这次是§8.4.8

  

在逐个签名的基础上覆盖或隐藏方法。

也就是说,要覆盖或隐藏父类中的方法,子类必须定义一个具有相同签名的方法 - 基本上,相同数量和类型的参数(尽管泛型和类型擦除使规则比这更复杂一些)。还有关于返回类型和throws子句的规则,但这些似乎与此问题无关。

请注意,您可以在子类中使用相同的 name 定义一个方法,作为父类(或实现的接口)中的方法,但具有不同数量或类型的参数。在这种情况下,你重载方法名称,既不覆盖也不隐藏任何东西;子类方法是一种新方法,几乎​​与继承的方法无关。 (当编译器必须将方法与方法调用匹配时,存在一种交互,但这是关于它的。)

现在提出您的问题:术语辅助功能隐藏(以及可见性)是Java中的独立概念。正如你所说,有一个&#34;原则&#34;一个子类根本没有办法减少继承方法的可访问性。无论您是重写实例方法还是隐藏类方法,这都适用。来自the JLS §8.4.8.3

  

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

     
      
  • 如果重写或隐藏方法为public,则覆盖或隐藏方法必须为public;否则,发生编译时错误。

  •   
  • 如果被覆盖或隐藏的方法为protected,则覆盖或隐藏方法必须为protectedpublic;否则,发生编译时错误。

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

  •   

总之,隐藏static方法的事实与更改方法的可访问性无关。

答案 1 :(得分:1)

基于hagubear的宝贵评论,似乎声明的作者意味着通过使用具有相同声明的方法重载来隐藏方法。

引用此link

  

我们可以在子类中声明具有相同签名的静态方法,但它   因为不会有任何运行时,所以不会被认为是重写   多态性。 (...)如果派生类定义了一个   与基类中的静态方法具有相同签名的静态方法,   派生类中的方法隐藏了基类中的方法。

因此,在具有完全相同声明的子类中定义方法有效地隐藏了子方法中的原始方法。但是,如果是字段,则转换为父级将恢复原始访问权限。

示例代码:

public class Test {
    public static void main( String[] args ) {
        B b = new B();
        A a = b;
        b.f(); // "Access somewhat denied"
        a.f(); // "f()"
    }
}
class A { 
    public static void f() { 
         System.out.println("f()");
    }
}
class B extends A { 
    // *must* be public
    public static void f() { 
         System.out.println("Access somewhat denied");
    }
}

答案 2 :(得分:0)

所以我创造了一个微不足道的测试; IntelliJ确实拒绝了它......是的,我知道&#34;它是一种工具......但我信任的一种工具#34;。在任何情况下,我都去了javac,它发出了相同的错误:

Error:(...) java: ...Concrete.java:5: doSomethingStatic() in 
...Concrete cannot override doSomethingStatic() in 
...Base; attempting to assign weaker access privileges; was public

基于此,以及我们一般的怀疑,我建议您的文档中存在错误。

以下是我的示例代码,我认为相当明确。它是protected的barfs。

public class Base
{
    public static void doSomethingStatic(){}
}

public class Concrete extends Base
{
    protected static void doSomethingStatic(){}
}

答案 3 :(得分:-2)

它可以通过派生类中的重载重新声明隐藏:

class Base
{
    public static void doSomethingStatic(){}
}

class Derived extends Base
{
    public static void doSomethingStatic(String arg){}
}

但仅对尝试通过派生类访问它的人隐藏。