Saturday 27 February 2016

Understanding Default methods in Java 8

Background

Based on our knowledge till Java 7 we know that methods in an interface are by default public and abstract and that you cannot have a non abstract method in interface. However this does not hold true from Java 8 with the introduction of default methods. You can declare a method default and provide it's body in the interface itself and you need not implement it in the classes that implement corresponding interface (You can definitely override it though).



Need for default methods

Lets say you have following interface -

public interface Movable {
    String walk();
}

and following class that implements it - 

public class Human implements Movable {

    @Override
    public String walk() {
        return "Human is walking";
    }

}

Now lets say your needs change  and you need to incorporate running as well. You would probably add a run() method in your Movable interface.

public interface Movable {
    String walk();
    String run();
} 

But this will break your Human class as you will have to implement run() method in Human class (or any other class that implements Movable interface). You will get following compilation error - 

  • The type Human must implement the inherited abstract method Movable.run()

To avoid such a situation we can use default methods.

Default Methods in Java 8

To add a default method in interface you need to use default keyword in your method declaration -

public interface Movable {
    String walk();
    default String run() {
        return "Moavable Object is running";
    }
}

and run your class as follows -

public class Human implements Movable {

    @Override
    public String walk() {
        return "Human is walking";
    }
    
    public static void main(String args[]){
        Movable movable = new Human();
        System.out.println(movable.walk());
        System.out.println(movable.run());
    }

}

You will get - 

Human is walking
Moavable Object is running

You can ofcourse override your default method as it suits you but notice that this does not break your existing code.


public class Human implements Movable {

    @Override
    public String walk() {
        return "Human is walking";
    }
    
    @Override
    public String run() {
        return "Human is running";
    }
    
    public static void main(String args[]){
        Movable movable = new Human();
        System.out.println(movable.walk());
        System.out.println(movable.run());
    }

}

And you should get -

Human is walking
Human is running

Multiple interface conflicts

Conflict will arise if you have default method with same signature in two interfaces and a class implements them both - 

public interface A {
    default String testMethod(){
        return "Called from A";
    }
}

public interface B {
    default String testMethod(){
        return "Called from B";
    }
}

public class Test implements A,B {
    public static void main(String args[]) {
        Test test = new Test();
        System.out.println(test.testMethod());
        
    }
}

Above code will not compile with following compilation error -
  • Duplicate default methods named testMethod with the parameters () and () are inherited from the types B and A
Alternatives here would be to override method in the class -

public class Test implements A,B {
    
    @Override
    public String testMethod(){
        return "Called from Test";
    }
    
    public static void main(String args[]) {
        Test test = new Test();
        System.out.println(test.testMethod());
       
    }
}


This should print -
Called from Test


OR if you want implementation of any specific interface you can do -

public class Test implements A,B {
    
    @Override
    public String testMethod(){
        return A.super.testMethod();
    }
    
    public static void main(String args[]) {
        Test test = new Test();
        System.out.println(test.testMethod());
        
    }
}


In this case you will get -
Called from A

NOTE : If an interface has no direct superinterfaces, then the interface implicitly declares a public abstract member method m with signature s, return type r, and throws clause t corresponding to each public instance method m with signature s, return type r, and throws clause t declared in Object, unless an abstract method with the same signature, same return type, and a compatible throws clause is explicitly declared by the interface. (JLS)

Though you can specify methods from Object in an interface you cannot override them. For eg. -

    interface A{
        void test();
        default boolean equals (Object obj){    
        }
    }


will fail compilation with -
  • A default method cannot override a method from java.lang.Object 
OR

    interface A{
        void test();
        static boolean equals (Object obj){   
        }
    }


will fail compilation with -
  • This static method cannot hide the instance method from Object

Related Links

t> UA-39527780-1 back to top