Search code examples
javainterfacedefault

@Override, with default methods in interfaces


I've been reading through some questions here on SO concerning the use of @Override in Java. (e.g. this one on override and this one on default methods, and obviously the documentations) However, I am still confused.

I was taught to always use and implement an interface when all behaviour in that interface needed to be used by a class. I get that. But as I was taught, you would do something like this (partially taken from the docs):

public interface TimeClient {
    void setTime(int hour, int minute, int second);
}

Which is then implemented by a class.

public class TestSimpleTimeClient implements TimeClient {
    public static void main(String[] args) {
    }

    @Override
    public void setTime(int hour, int minute, int second) {
         System.out.println(hour + " " + minute + " " +second);
    }
}

The thing that bugs me is the implementation of the method in the interface. It doesn't do anything, it's only declared as a method that take arguments but doesn't do anything else. Then you take that method and Override it in a class that implements that interface.

I understand that this is a way to "force" classes to implement a method but I don't see how this is useful in some specific use cases.

Let's say I have an interface that's implemented by a couple of classes. I want most of these classes to share the same implementation of the method, but not all. The logical, and character-efficient way would be to have a way to say: these classes take the default method in the interface, but these classes override the default method. How would I go about doing that? Should the one that overrides the method only implement it, whereas the ones that simply use the default method as a whole extend it? And what if you only want this behaviour for a specific method in an interface?


Solution

  • The thing that bugs me is the implementation of the method in the interface. It doesn't do anything, it's only declared as a method that take arguments but doesn't do anything else.

    That is not an "implementation of the method in the interface". That's just an interface method declaration. In programming, terminology matters. Interfaces tend to be devoid of any implementations. (Unless you are talking about the default interface methods of Java 8, but from the rest of your question it is unclear whether you are aware of their existence.)

    I understand that this is a way to "force" classes to implement a class

    A class cannot implement a class. A class extends a class. But a class implements an interface. In programming, terminology matters a lot.

    It is not just a way to force classes to provide an implementation. It is also a way for callers to be able to invoke an interface method without having to know anything about the class that implements it.

    but I don't see how this is useful in some specific use cases.

    Well, take for example the Collection<T> interface, and the contains() method, which is implemented by a myriad of classes, among which ArrayList<T>, LinkedList<T>, HashSet<T>, BoundedBlockingQueue<T>, and so on, and so forth. Your code may look like this:

    boolean hasPekingese( Collection<Animal> animals )
    {
        return animals.contains( AllOfMyAnimals.PEKINGESE );
    }
    

    Note how the hasPekingese() method does not have to know the exact class that is implementing Collection<Animal>. Which means that you may invoke hasPekingese() from a class which keeps its animals in an ArrayList<Animal>, and you may also invoke hasPekingese() from a class which keeps its animals in a BoundedBlockingQueue<Animal>. The method hasPekingese() does not know, and does not care.

    Let's say I have an interface that's shared by a couple of classes.

    It is unclear what you mean by "shared". Do you mean "implemented"? In programming, terminology is of paramount importance.

    I want most of these classes to share the same implementation of the method, but not all. The logical, and character-efficient way would be to have a way to say: these classes take the default method in the interface, but these classes override the default method. How would I go about doing that?

    There are many ways to go about that, the most common being to have some of these classes extend some common base class, which provides the common implementation of your method, so that the derived classes inherit this method, so they do not have to implement it. The rest of the classes do not extend that common base class, so each one of them has to provide its own implementations of that method.

    Should the one that overrides the method only implement it, whereas the ones that simply use the default method as a whole extend it?

    That's not clear. Also, please do not call it a "default method", because as of Java 8 "default method" is a term that has a very specific meaning, and although it is related to this discussion, it is different from the sense in which you are using it.

    And what if you only want this behaviour for a specific method in an interface?

    If a derived class wants the method to work differently, it may re-override it. Or, you may have two different base classes, one which implements the method in a certain way, and another which implements it differently, so half of your derived classes extend the first base class, while the other half of your derived classes extend the second base class.