Why are class static methods inherited but not interface static methods?
I understand that in Java static methods are inherited just like instance methods, with the difference that when they are redeclared, the parent implementations are hidden rather than overridden. Fine, this makes sense. However, the Java tutorial notes that
Static methods in interfaces are never inherited.
Why? What's the difference between regular and interface static methods?
Let me clarify what I mean when I say static methods can be inherited:
class Animal {
public static void identify() {
System.out.println("This is an animal");
}
}
class Cat extends Animal {}
public static void main(String[] args) {
Animal.identify();
Cat.identify(); // This compiles, even though it is not redefined in Cat.
}
However,
interface Animal {
public static void identify() {
System.out.println("This is an animal");
}
}
class Cat implements Animal {}
public static void main(String[] args) {
Animal.identify();
Cat.identify(); // This does not compile, because interface static methods do not inherit. (Why?)
}
Solution 1:
Here's my guess.
Since Cat
can only extend one class if Cat
extends Animal
then Cat.identify
has only one meaning. Cat
can implement multiple interfaces each of which can have a static implementation. Therefore, the compiler would not know which one to choose?
However, as pointed out by the author,
Java already has this problem, with default methods. If two interfaces declare default void identify(), which one is used? It's a compile error, and you have to implement an overriding method (which could just be Animal.super.identify()). So Java already resolves this problem for default methods – why not for static methods?
If I was to guess again, I'd say that with default
the implementation is part of Cat
's vtable. With static
it cannot be. The main function must bind to something. At compile time Cat.identify
could be replaced with Animal.identify
by the compiler but the code wouldn't match reality if Cat
was recompiled but not the class that contains main.
Solution 2:
Before Java 8, you couldn't define static
methods in an interface
. This is heavily discussed in this question. I'm going to refer to this answer (by user @JamesA.Rosen) as to why the Java designers probably didn't want static
methods in an interface
initially:
There are a few issues at play here. The first is the issue of declaring a static method without defining it. This is the difference between
public interface Foo {
public static int bar();
}
and
public interface Foo {
public static int bar() {
...
}
}
Java doesn't allow either, but it could allow the second. The first is impossible for the reasons that Espo mentions: you don't know which implementing class is the correct definition.
Java could allow the latter, as long as it treated Interfaces as first-class Objects. Ruby's Modules, which are approximately equivalent to Java's Interfaces, allow exactly that:
module Foo
def self.bar
...
end
end
However, since the release of Java 8, you can actually add default
and static
methods inside an interface
.
I'm going to be quoting this source a lot here. This is the initial problem:
Java's interface language feature lets you declare interfaces with abstract methods and provide implementations of those methods in the classes that implement the interfaces. You are required to implement each method, which is burdensome when there are many methods to implement. Also, after publishing the interface you cannot add new abstract methods to it without breaking source and binary compatibility.
This was the solution Java 8 provided default
:
Java 8 addresses these problems by evolving the interface to support default and static methods. A default method is an instance method defined in an interface whose method header begins with the default keyword; it also provides a code body. Every class that implements the interface inherits the interface's default methods and can override them
And for static
:
A static method is a method that's associated with the class in which it's defined, rather than with any object created from that class. Every instance of the class shares the static methods of the class. Java 8 also lets static methods be defined in interfaces where they can assist default methods.
When you implement an interface that contains a static method, the static method is still part of the interface and not part of the implementing class. For this reason, you cannot prefix the method with the class name. Instead, you must prefix the method with the interface name
Example:
interface X
{
static void foo()
{
System.out.println("foo");
}
}
class Y implements X
{
}
public class Z
{
public static void main(String[] args)
{
X.foo();
// Y.foo(); // won't compile
}
}
Expression
Y.foo()
will not compile becausefoo()
is a static member of interfaceX
and not a static member of classY
.