Why if static method don't involve in polymorphism(late binding) I see error that static method cannot be overridden

StackOverflow https://stackoverflow.com/questions/23573726

Вопрос

please consider following code:

class A{
    public static void m(Number n){
         System.out.println("Number A");
    };
}
class B extends A{
     public static int m(Number n){
        System.out.println("Number B");
        return 1;
      };
}

output:

java: m(java.lang.Number) in inheritanceTest.B cannot override m(java.lang.Number) in inheritanceTest.A return type int is not compatible with void

I know that static methods doen't involve in polymorphism hence I infer that overriding is impossible for my code. This compiler message is strange for me.

As I understand that overriding is part of polymorphism. I prepare for scjp and I am afraid make mistake in familiar question.

Please clarify this issue.

expected behaviour for me - message about overloading error

P.S1.

I have read top popular question about static overridden and I didn't found answer(

P.S2. According Pshemo answer:

this code:

class Foo{
    public static void m(Number n){
         System.out.println("Number A");
    };
    public static int m(Number n){
        System.out.println("Number B");
        return 1;
    };
}

outputs:

error: method m(Number) is already defined in class Foo
    public static int m(Number n){
                      ^
1 error

For me these situations are same. But compiler error is different - strange.

Это было полезно?

Решение

JLS §8.4.8.3 (Java 8) says:

If a method declaration d1 with return type R1 overrides or hides the declaration of another method d2 with return type R2, then d1 must be return-type-substitutable (§8.4.5) for d2, or a compile-time error occurs.

This same rule applies both to instance methods and static methods, since it says "overrides or hides". Basically, if you have a method with the same name and same parameters, it overrides if it's an instance method, but hides (the inherited method) if it's a class (static) method. And in both cases, the return type must either be the same or obey the rules for covariance.

Since it's the same rule, most likely there's just one place in the compiler code that checks this rule, and if the rule is violated you're getting the error you're seeing, which I'm sure is a much more common occurrence. The compiler really should check to see whether it should say "overrides" or "hides", but it looks like they slipped. Getting error message exactly right is not usually the highest priority of compiler writers--not compared to making sure code that's supposed to compile does so and runs right, and code that isn't supposed to compile doesn't. So I think this is a deficiency, but a very minor one.

Другие советы

Even if static methods can't be overridden they are still inherited so what you are trying to do would lead to situation similar to

class Foo{
    public static void m(Number n){
         System.out.println("Number A");
    };
    public static int m(Number n){
        System.out.println("Number B");
        return 1;
    };
}

which is wrong because you can't have two methods with same signature but with different return types. Reason why it was forbidden is quite simple... Lets say we have methods:

  • Foo method(){ return new Foo(); }
  • Bar method(){ return new Bar(); }

and you would want to invoke them like

System.out.println(method());

Should result be Foo or Bar? Compiler wouldn't be able to decide.

To prevent this kind of situations compiler forbids overriding/hiding methods with same signature by changing its return types. Only exception is when you are changing return type to more detailed one like

class X{
    List<String> m(){...}
}

class Y extends X{
    LinkedList<String> m(){...}
}

So it seems that override is not best word here. Correct word should be hide since static methods can be hidden, not overridden. But it looks like same rules (or at least some portion of them) are used to test if we can hide method as rules for overriding, so in case of problem same error message is shown (about overriding instead of hiding), which can be misleading.

I think the compiler error usage of 'override' is misleading here, it isn't applicable.

The language spec says:

If a method declaration d1 with return type R1 overrides or hides the declaration of another method d2 with return type R2, then d1 must be return-type substitutable for d2, or a compile-time error occurs.

Here your B method is hiding the declaration of A.m:

If a class declares a static method m, then the declaration m is said to hide any method m', where the signature of m is a subsignature (§8.4.2) of the signature of m', in the superclasses and superinterfaces of the class that would otherwise be accessible to code in the class.

If your B class did not have an m method, then you could call B.m and it would call the m defined on A.

Having B.m is hiding A's version of m. Because you can call a static method defined on a superclass but reference the subclass, that sets up some expectations about the method that are violated by the different return type.

It's hiding and not overriding because if you have a B.m defined, you can still call A.m and get the superclass' version of the method. With overriding it's the runtime type that decides what gets called and how it's called does not matter.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top