2

Consider the following snippet:

interface Super{
    public static void doIt(){}
}
class Sub implements Super{
    public void doIt(){}
}
  • Here I have declared a static member method and it is being redeclared as the instance method in the child class.
  • This is allowed by the compiler - but when I do the same with the superclass and subclass types - this gives compilation error:
class Super{
    public static void doIt(){}
}
class Sub extends Super{
    public void doIt(){}
}
  • What is the rationale behind the same? - ideally the way to access the subclass is essentially the same - then why this restriction?
theutonium.18
  • 483
  • 2
  • 7
  • I suspect that the compiler is preventing a bug. Because static methods on a superclass can be invoked on instances (yes, with a warning), this may end up being misleading... `subObject.doIt()` would be calling which method? You can't use `subObject.doIt()` to call `Super.doIt()` if `Super` is an interface, the compiler already prohibits that. – ernest_k Nov 04 '21 at 09:31
  • The members that are the part of the instance of a class are overridden (i.e public and protected) , static members aren't the part of the instance of a class, its the part of actual class. – Fahad-Android Nov 04 '21 at 10:25

1 Answers1

1

The reason for this is that Java allows invoking static methods in a non-static manner. Consider this example:

public class MyClass {
    public static void sayHello() {
    }

    public void test() {
        this.sayHello();
    }
}

This will produce a compiler warning (The static method sayHello() from the type MyClass should be accessed in a static way), but it will compile and invoke the static method correctly at runtime.

That's why the following code will not compile because of an ambiguity (Duplicate method test() in type MyClass):

public class MyClass {
    public static void test() {
    }

    public void test() {
    }
}

The reason for the compile error is, that if you write the following, the compiler cannot know which method to invoke, because it allows to call static methods in a non-static manner:

public class MyClass {
    public static void test() {
    }

    public void test() {
    }

    public void execute() {
        this.test();
    }
}

For the same reason it is not possible to have the static test() method in the parent class - the same rules apply. It is possible in Java to call static methods of super classes with or without qualification:

public class Super {
    public static void test() {
    }
}

public class Sub extends Super {
    public void execute() {
        this.test();
    }
}

OR

public class Sub {
    public void execute() {
        test();
    }
}

where the invocation of this.test() will produce a warning, but will work at runtime.

For static methods in interfaces, the above example will not work, because the compiler forces you to call the static method of the interface in a qualified manner (edit: because they are not being inherited). The following will not work (The method interfaceStatic() is undefined for the type Sub):

public interface Interface {
    public static void interfaceStatic() {  
    }
}

public class Sub implements Interface {
    public void test() {
        interfaceStatic();
    }
}

In order to call interfaceStatic() the invocation has to be qualified like this:

public class Sub implements Interface {
    public void test() {
        Interface.interfaceStatic();
    }
}

That's the difference between defining the static method in an interface and defining it in the super class: The way of invocation. If you implement multiple interfaces which all have a static method with the same signature, the compiler cannot know which one to call.

This is the reason why it is allowed to define a static method with the same signature in an implemented interface, but not in the parent classes.

majusebetter
  • 1,458
  • 1
  • 4
  • 13
  • 1
    A static interface method still can be invoked without qualifier when it is is scope, e.g. `public interface Interface { public static void interfaceStatic() {} default void instanceMethod() { interfaceStatic(); /* but not this.interfaceStatic(); */ } }`. Likewise, a different class can use it as `interfaceStatic();` when it has an appropriate `import static …;` statement. But static interface methods are *not inherited*, so they are not in scope of implementation classes, unless they contain an `import static …;` statement. Since the implementation doesn’t inherit it, there’s no conflict. – Holger Nov 05 '21 at 12:26
  • @Holger Yes, that's true. But this is a different story and not within the scope of the question. If you import explicitly via `import static`, you have to deal with conflicting method signatures yourself in the importing class. The question is about the "duplicate definition" error. As you know, `static` methods belong to the class, not the instance. If Java would enforce using the `this` keyword for all *instance* members, there would be no problem at all, since the compiler always knows what you're referring to (class- or instance member). E.g. TypeScript allows what the OP is asking for. – majusebetter Nov 05 '21 at 13:18
  • @Holger Don't get me wrong: You say "static methods are not inherited" - and that's definitely true. But I think the OP wanted to know *why* the static methods of the interface are not reflected into the scope of the implementing classes. And that's what I was trying to explain. – majusebetter Nov 05 '21 at 13:26
  • 1
    The OP wanted to know why the declaration `public void doIt(){}` is accepted in `class Sub implements Super` and the answer is, because `Sub` does not inherit the `public static void doIt(){}` method from `Super`. If you tried to declare that method within `Super`, you’d still get an error, i.e. `interface Super{ public static void doIt(){} public void doIt(); }` does not compile, despite the fact that you can’t do `this.doIt()` for the `static` interface method. Whether you can distinguish invocations, is irrelevant. – Holger Nov 05 '21 at 14:45
  • You can see the question from two sides here. One side is, why it is not possible to declare two methods with the same signature on class- and instance member level. The other part is, why it is allowed with interfaces. My explanation tried to cover both aspects. – majusebetter Nov 05 '21 at 15:52
  • BTW, the fact that you have to call the static interface method in a qualified way (or use `import static`) already implies that the method is not inherited. – majusebetter Nov 05 '21 at 15:57
  • 1
    You have it backward. The fact that the method is not inherited is the reason for all the other things, not just implied by them, and hence, the answer to the *why* question. – Holger Nov 05 '21 at 18:02
  • As I tried to point out, saying the "method is not inherited" does not answer the question why it is not possible two have two methods with the same signature in class- and instance scope. This is something related to Java and some other languages. Some languages that allow this. For me, saying "method is not inherited" (what I also pointed out), is only half the answer. – majusebetter Nov 06 '21 at 10:30
  • 1
    The question wasn’t “*why does Java not allow this*” but “*why is this declaration possible in case of a class implementing an interface*” and the answer precisely is “*because in this case, the class does not inherit the contradicting method*”. You are trying to answer a question than hasn’t been asked. – Holger Nov 08 '21 at 08:25