Why are class static methods inherited but not interface static methods?

14,247

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 because foo() is a static member of interface X and not a static member of class Y.

Solution 3

Static methods in interfaces could create a diamond of death if they were being inherited. So, calling a static method from the appropriate interface is good enough compared to the risk of calling it from a concrete class that may implement multiple interfaces that contain static methods of the same name.

Why are static methods any different?

Static methods are just functions unrelated to the objects. Instead of placing them in utility abstract classes (like calling Collections.sort() ) we move those functions (static methods) to their appropriate interfaces. They could be bound to the inherited objects like the default methods do, but that is not their job. Static methods provide functionality which is unrelated to the instances of the class.

Example:

interface Floatable {

    default void float() {
        // implementation
    }

    static boolean checkIfItCanFloat(Object fl) {
         // some physics here
    } 
}

class Duck implements Floatable { }

So, the point is that a Duck may float but the function that checks if an Object really floats is not something that a Duck can do. It is an irrelevant functionallity that we could pass to our Floatable interface instead of having it sit inside some utility class.

Solution 4

Let's begin with some background ...

Java doesn't support multiple inheritance (the ability to extend more than one class). This is because multiple inheritance is prone to the deadly diamond of death (also known as the diamond problem) which the designers of Java chose to preempt.

enter image description here

If B and C override a method inherited from A, which method does D inherit?

A class can implement multiple interfaces because interface methods are contracted for overriding; if a class C implements two interfaces A and B that declare the same method, then the same method in C will be invoked by clients of either interface (A or B). The introduction of default methods for interfaces in Java 8 was made possible by forcing the implementer to override the default in case of ambiguity. This was an acceptable compromise since default methods are intended to be defensive (to be used if no other implementation is explicitly provided by an implementer). However, since the compiler can’t force you to override a static method (static methods inherently can't be overridden), the introduction of static methods for interfaces in Java came with one restriction: the static methods of an interface are not inherited.

Share:
14,247
Radon Rosborough
Author by

Radon Rosborough

Updated on June 17, 2022

Comments

  • Radon Rosborough
    Radon Rosborough almost 2 years

    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?)
    }
    
  • Radon Rosborough
    Radon Rosborough almost 10 years
    This makes sense, but don't we already have a diamond of death problem with default methods? And doesn't the compiler have resolution support for this (i.e., forcing you to implement a new method to resolve ambiguous default inheritance)? Why are static methods any different?
  • William F. Jameson
    William F. Jameson almost 10 years
    +1, but I was just writing a comment to the same effect. The answer should point out why the same (or analogous) mechanism fails for static methods.
  • William F. Jameson
    William F. Jameson almost 10 years
    @raxod502 One could argue that the inheritance of static members was a mistake in the first place, and that they made the right choice here. You really don't want your class polluted by all the static methods from its interfaces, let alone be forced to introduce bogus static methods just because you have a collision.
  • William F. Jameson
    William F. Jameson almost 10 years
    This is what OP knows. He's asking why it is specified like this, in opposition to class's static members.
  • But I'm Not A Wrapper Class
    But I'm Not A Wrapper Class almost 10 years
    @WilliamF.Jameson Updated answer :)
  • William F. Jameson
    William F. Jameson almost 10 years
    Your edit makes a case which is as valid for class's static methods (which are inherited) as for interface's static methods. So then the question is, why are static methods inherited by a subclass?
  • Radon Rosborough
    Radon Rosborough almost 10 years
    Okay... but if the problem is ambiguous inheritance of methods, then the question becomes: "We already have this issue, with default methods. Since Java includes support for resolution of default inheritance conflicts (see comment on Styl's answer), why is static inheritance any different?"
  • fIwJlxSzApHEZIl
    fIwJlxSzApHEZIl over 7 years
    @CyberneticTwerkGuruOrc this is great but I still haven't figured out how to do multiple inheritance for static methods. If I use an interface I have to wrap the interface's static method call with a static call of the implementing class. If I use a subclass I can't have multiple inheritance. It still looks pretty murky from where I'm sitting.
  • Ajax
    Ajax over 5 years
    @RadonRosborough default methods can by inherited because there are rules about forcing you to choose which super to call if you inherit both. Static methods cannot be overridden, ergo, there is no mechanism make the developer pick which one, short of just creating a new static method (what you'd have to do now if you really need that static method to have a particular class... Keeping in mind you always have to specify the enclosing class when calling static methods anyway).
  • Ajax
    Ajax over 5 years
    The gotcha that brought me here was the fact that classes implementing an interface with a static method cannot call that method without fully qualifying it either. No free lunch, eh?
  • Ng Sharma
    Ng Sharma about 4 years
    thank for sharing appropriate answer @ButI'mNotAWrapperClass.
  • wlnirvana
    wlnirvana over 3 years
    Technically, one cannot override (in the sense of dynamic dispatch) a static method as of Java 15, even for classes. But even this is a debatable design.
  • shiva
    shiva almost 3 years
    @agbinfo "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" - Can you please help me understand this point? Do you mean if we have statement "Cat.identify()" in the main() method, compiler wouldn't know if it needs to call Animal.identify() or Cat.identify()? If this is the case then doesn't this occur when we have static methods in parent class but hide them in child class? I am not able to understand this part.
  • agbinfo
    agbinfo almost 3 years
    @shiva It's been a very long time since I programmed in Java. That said, when calling a static method, don't you need to specify the class name? So Cat.identify() would be meaningless unless it has a definition to begin with. This is not the case if I call instance.identify()
  • shiva
    shiva almost 3 years
    @agbinfo Yes, it'll require class name. But why can't compiler ensure the Cat.identify() has a definition of the static method? The original question was why aren't static methods in interfaces are inherited. The obvious answer is because a class may implement two interfaces and both may have the same method. But this problem was solved in default methods by enforcing the class to provide its version. What I did not understand from your answer is why can't the same thing be enforced for static methods as well?
  • agbinfo
    agbinfo almost 3 years
    @shiva The compiler could ensure that Cat.identify() has a definition but my understanding is that when you call Cat.identify() you're calling the most "derived" version of the identify() method. Not just a different method. When calling Cat.identify() for the derived class, you are allowing the developer to eventually provide a definition for identify() that is better defined for that class without changing the remainder of the code. For the static interface method, there's just no benefit I can think of. If you want a different method can't you just give it a different name?