Reducing the visibility of a static method

2020-02-06 03:31发布

I know that a child cannot reduce the visibility of a non-static method and I understand why it is so.

I've read however that "static method can be hidden through its redeclaration". I however do not understand how this could be achieved in Java.

Is this really possible? If yes, how to do that (code example) and why was it introduced (it seems to contradict the principle of non-reducing the visibility of the interface)?

4条回答
狗以群分
2楼-- · 2020-02-06 04:10

Based on hagubear's valuable comments, it seems that the author of a statement meant hiding a method through overloading it with a method having the same declaration.

Quoting this link:

We can declare static methods with same signature in subclass, but it is not considered overriding as there won’t be any run-time polymorphism. (...) If a derived class defines a static method with same signature as a static method in base class, the method in the derived class hides the method in the base class.

Thus, defining a method in a child class having exact same declaration effectively hides the original method in child. However, as in case of fields, casting to the parent will restore the original access.

Sample code:

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");
    }
}
查看更多
Evening l夕情丶
3楼-- · 2020-02-06 04:14

The short answer is: no, it is not possible. You have mixed up some terminology. Hiding has nothing to do with accessibility (which is what you are really asking about, not visibility, which is related to scope and shadowing and is discussed in Chapter 6 of the Java Language Specification (JLS)).

Now for the longer answer. The term overriding applies to instance methods, while the term hiding applies to class (static) methods. From the Java Tutorial topic Overriding and Hiding Methods:

The distinction between hiding a static method and overriding an instance method has important implications:

  • The version of the overridden instance method that gets invoked is the one in the subclass.
  • The version of the hidden static method that gets invoked depends on whether it is invoked from the superclass or the subclass.

Some of the other answers here provide incorrect examples about method hiding, so let's go back to the JLS, this time to §8.4.8:

Methods are overridden or hidden on a signature-by-signature basis.

That is, to override or hide a method in the parent class, the subclass must define a method with the same signature—basically, the same number and type of arguments (although generics and type erasure makes the rules a little more complicated than that). There are also rules about return types and throws clauses, but those seem irrelevant to this question.

Note that you can define a method in a subclass with the same name as a method in the parent class (or in an implemented interface) but with different number or type of arguments. In that case, you are overloading the method name and neither overriding nor hiding anything; the subclass method is a new method, pretty much independent of the inherited method(s). (There is an interaction when the compiler has to match methods to method calls, but that's about it.)

Now to your question: the terms accessibility and hiding (as well as visibility) are independent concepts in Java. There is, as you put it, a "principle" that there is simply no way for a subclass to reduce the accessibility of an inherited method. This applies regardless of whether you are overriding an instance method or hiding a class method. From the JLS §8.4.8.3:

The access modifier (§6.6) of an overriding or hiding method must provide at least as much access as the overridden or hidden method, as follows:

  • If the overridden or hidden method is public, then the overriding or hiding method must be public; otherwise, a compile-time error occurs.

  • If the overridden or hidden method is protected, then the overriding or hiding method must be protected or public; otherwise, a compile-time error occurs.

  • If the overridden or hidden method has default (package) access, then the overriding or hiding method must not be private; otherwise, a compile-time error occurs.

In summary, the fact that a static method can be hidden has nothing to do with changing the accessibility of the method.

查看更多
唯我独甜
4楼-- · 2020-02-06 04:23

It can be hidden by an overloaded redeclaration in a derived class:

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

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

but only hidden to people who try to access it via the derived class.

查看更多
一纸荒年 Trace。
5楼-- · 2020-02-06 04:28

So I created a trivial test; IntelliJ indeed rejected it... and Yes, I know "it's a tool...but one I trust". In any case, I went to javac, which emitted the same ERROR:

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

Based on this, and our skepticism in general, I suggest the error is in your documentation.

Below is my sample code, fairly definitive I think. It barfs at the protected.

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

public class Concrete extends Base
{
    protected static void doSomethingStatic(){}
}
查看更多
登录 后发表回答