Java 8 – default and static methods in Interface

In previous article, we have seen and learnt that defining constructor inside interface is not allowed and compiler throws error stating below reason

Interface in Java :

Compile-time error:Interfaces cannot have constructors

1_Interface_in_Java_8_constructor_error

Constructor are needed to construct a new object to hold the state of an object and invoke member methods, but in Interface

  • There are only static variables
  • By default all variables are public, static and final (i.e.; constants)
  • Methods with no concrete implementation (i.e.; all are abstract methods)

Which makes it clear that, we don’t need constructor to construct an object of Interface. Also, we cannot instantiate Interface and compiler throws error stating below reason

Compile-time error:Cannot instantiate the type <Interface-name>

2_Interface_in_Java_8_cannot_instantiate_type_interface

Question arises, who is going to provide concrete implementations to these abstract methods and how to access “static” variables,

  • All implementing classes must provide concrete implementation to all abstract methods declared inside interface
  • To access constants, use Interface name for example <Interface-name>.<variables-name>

Example to demonstrate implementation of abstract methods and accessing constants

DemoInterfaceImpl.java

package in.bench.resources.itf.example;

interface DemoInterface {

	int AGE = 2;
	String NAME = "BenchResources.Net";

	void publishArticles();
}

public class DemoInterfaceImpl implements DemoInterface {

	@Override
	public void publishArticles() {
		System.out.println("Age  : " + DemoInterface.AGE);
		System.out.println("Name : " + DemoInterface.NAME);
	}

	public static void main(String[] args) {

		DemoInterfaceImpl demo = new DemoInterfaceImpl();
		demo.publishArticles();
	}
}

Output:

Age  : 2
Name : BenchResources.Net

All points discussed stand true for interface even in Java 8. But with the release of Java 8, some new and exciting featured are added

One such feature is defining concrete methods inside Interface i.e.;

  • default method (prefixing with default keyword)
  • static method (prefixing with static keyword)

Note: Prior to Java 8 release, only abstract methods are allowed in interface

1. Need of introducing “default” method in Interface

Declaring methods inside interface, makes implementing classes to provide concrete implementation or else make implementing class as abstract

Which means we got two options while implementing interface i.e.;

  • implement all abstract methods
  • declare class as abstract, if we want to go for partial implementation

Even if we declare one more abstract method in interface, it becomes quite cumbersome for all implementer classes to implement abstract method forcefully (Really, no choice huh!!)

Q) What if there are more than 100 classes implementing this interface ?

  • Till now only solution is to make our hands dirty by implementing abstract method or making implementing classes as abstract (both are forceful action on developer end)
  • But with the release Java 8, the new cool feature is added i.e.; if any new method need to be added then provide default implementation for this new method inside interface itself
  • This new method will be prefixed with “default” keyword and known as default method in Java 8
  • In Java 8, default methods are alternatively referred as Virtual Extension methods or defender methods for their role in interface
  • Now implementing classes can override & provide more specific implementation, if required or else they can still use default implementation provided from interface
  • This way, new method added inside interface doesn’t forces developer to implement rather it provides default implementation and all implementer classes can relax and whenever required can override & provide implementation
  • Note: This cool feature is added to achieve loose coupling with interface and backward compatibility

Let us see an example for default method

InterfaceInJava8.java

package in.bench.resources.itf.example;

// only public and abstract are permitted
public interface InterfaceInJava8 {

	// old abstract method
	void displayAbstractMethod(); // by default, this is public and abstract

	// default method with concrete implementation from Java 8
	default void displayDefaultMethod() {
		System.out.println("InterfaceInJava8 : default method impl inside Java Interface");
	}
}

TestJava8InterfaceImpl.java

package in.bench.resources.itf.example;

public class TestJava8InterfaceImpl implements InterfaceInJava8 {

	// similar to abstract method, we can override default method too
	@Override
	public void displayAbstractMethod() {
		System.out.println("TestJava8InterfaceImpl : Implementing abstract method in this class\n");
	}

	public static void main(String args[]){

		// creating an object
		TestJava8InterfaceImpl impl = new TestJava8InterfaceImpl();

		// invoking abstract method implementation in this class
		impl.displayAbstractMethod();

		// invoking default method from interface
		impl.displayDefaultMethod();
	}
}

Output:

TestJava8InterfaceImpl : Implementing abstract method in this class

InterfaceInJava8 : default method impl inside Java Interface

But its look more like an abstract class i.e.; having both abstract and concrete methods, then why there is a need to introduce new “default” method in Java 8

2. Abstract class v/s Interface in Java 8

  • At a very high level, it looks very similar but actually they are different in many ways.
  • Also, considering the fact that default method in interface helps us to achieve loose coupling and backward compatibility
 
Sr. No.
 
 
Abstract Classes
 
Interface
1Contains members variablesAll variables are actually constants
2It can have constructorsInterface cannot have constructors
3Can hold state of an object using instance member variablesSince, all variables are static and final therefore no concept of holding state of an object
4Forces to implement abstract methods or else declare class as abstractdefault methods can be overridden, if required but never forces

3. Overriding or Implementing default method

  • As we all know, interface implementing class needs to provide concrete implementation for all abstract methods but can leave out default methods since there is always default implementation
  • But as we seen above, if it’s required to provide more specific implementation then we can override default method

Let us see an example for this case

InterfaceInJava8.java

package in.bench.resources.itf.example;

// only public &amp;amp; abstract are permitted
public interface InterfaceInJava8 {

	// old abstract method
	void displayAbstractMethod(); // by default, this is public and abstract

	// default method with concrete implementation from Java 8
	default void displayDefaultMethod() {
		System.out.println("InterfaceInJava8: default method impl inside Java Interface");
	}
}

TestJava8InterfaceImpl.java

package in.bench.resources.itf.example;

public class TestJava8InterfaceImpl implements InterfaceInJava8 {

	// overriding default method to provide specific implementation
	public void displayDefaultMethod() {
		System.out.println("TestJava8InterfaceImpl : overriding default method from interface\n");
	}

	// implementing abstract method
	@Override
	public void displayAbstractMethod() {
		System.out.println("TestJava8InterfaceImpl : Implementing abstract method in this class\n");
	}

	public static void main(String args[]){

		// creating an object
		TestJava8InterfaceImpl impl = new TestJava8InterfaceImpl();

		// invoking abstract method implementation in this class
		impl.displayAbstractMethod();

		// this times, invokes overriding default method in this class
		impl.displayDefaultMethod();
	}
}

Output:

TestJava8InterfaceImpl : Implementing abstract method in this class

TestJava8InterfaceImpl : overriding default method from interface

Note: While overriding, cannot reduce the visibility of the inherited method

4. Multiple inheritance problem and its solution

  • Again as we all know, Java doesn’t allow to extend multiple classes as it lead to classic diamond problem and happily allows to implement multiple interfaces
  • But this leads to ambiguity problem due to default methods in interface

Let us analyze ambiguity problem and later will find solution

Here, in the above example,

  • there are two interfaces with exactly same default methods (same signature)
  • a class implementing both interfaces

DemoInterfaceA.java

package in.bench.resources.itf.example;

public interface DemoInterfaceA {

	// default method with concrete implementation from Java 8
	default void displayDefaultMethod() {
		System.out.println("DemoInterfaceA : default method impl inside Java Interface");
	}
}

DemoInterfaceB.java

package in.bench.resources.itf.example;

public interface DemoInterfaceB {

	// default method with concrete implementation from Java 8
	default void displayDefaultMethod() {
		System.out.println("DemoInterfaceB : default method impl inside Java Interface");
	}
}

TestMultipleInheritance.java

package in.bench.resources.itf.example;

public class TestMultipleInheritance implements DemoInterfaceA, DemoInterfaceB {

}
3_Interface_in_Java_8_multiple_inheritance_ambiguity_problem

Compile-time error: Duplicate default methods named displayDefaultMethod with the parameters () and () are inherited from the types DemoInterfaceB and DemoInterfaceA

4.1 Solution for multiple inheritance:

While implementing both interfaces, just provide empty implementation to resolve ambiguity problem

Now provide implementation for this method in below ways,

  • altogether new implementation
  • invoke default implementation either of the interface
  • invoke default implementation of both interface (consider sequence while doing so)
  • or mix of all above points

Let us see an example for this case

Solution A: Invoke one of the default method from implementing interface using super keyword

TestMultipleInheritance.java

Syntax: <InterfaceName>.super.<defaultMethodName>

package in.bench.resources.itf.example;

public class TestMultipleInheritance implements DemoInterfaceA, DemoInterfaceB {

	// overriding default method with new concrete implementation
	public void displayDefaultMethod() {

		// invoking DemoInterfaceA's default method to resolve ambiguity problem
		DemoInterfaceA.super.displayDefaultMethod();
	}

	public static void main(String args[]) {

		TestMultipleInheritance mul = new TestMultipleInheritance();
		mul.displayDefaultMethod();
	}
}

Output:

DemoInterfaceA : default method impl inside Java Interface

Solution B: Provide new implementation for overriding default method

TestMultipleInheritance.java

Just write new logic for this overriding method

package in.bench.resources.itf.example;

public class TestMultipleInheritance implements DemoInterfaceA, DemoInterfaceB {

	// overriding default method with new concrete implementation
	public void displayDefaultMethod() {
		System.out.println("TestMultipleInheritance : overriding default method" + 
                                                      "with new concrete implementation");
	}

	public static void main(String args[]) {

		TestMultipleInheritance mul = new TestMultipleInheritance();
		mul.displayDefaultMethod();
	}
}

Output:

TestMultipleInheritance : overriding default method with new concrete implementation

4.2 Points to remember about default method in interface:

  • default methods are alternatively referred as Virtual Extension methods or defender methods
  • This could be used as utility methods
  • default method supports lambda expression which is again a new feature in Java 8

5. Need of introducing “static” method in interface

  • In addition to default methods, Java 8 introduces defining static method inside Interface
  • These static methods will act as helper methods and we can organize static methods inside an interface rather to any separate class

Let us see an example for static method

InterfaceInJava8.java

package in.bench.resources.itf.example;

// only public & abstract are permitted
public interface InterfaceInJava8 {

	// old abstract method
	void displayAbstractMethod(); // by default, this is public and abstract

	// static method with concrete implementation from Java 8
	static void displayStaticMethod() {
		System.out.println("InterfaceInJava8 : static method impl inside Java Interface");
	}
}

TestJava8InterfaceImpl.java

  • To invoke static method from interface, use interface name
  • Syntax: <Interface-Name>.<static-method-name>
package in.bench.resources.itf.example;

public class TestJava8InterfaceImpl implements InterfaceInJava8 {

	// implementing abstract method
	@Override
	public void displayAbstractMethod() {
		System.out.println("TestJava8InterfaceImpl : Implementing abstract method in this class\n");
	}

	public static void main(String args[]){

		// creating an object
		TestJava8InterfaceImpl impl = new TestJava8InterfaceImpl();

		// invoking abstract method implementation in this class
		impl.displayAbstractMethod();

		// invoking static method using Interface name
		InterfaceInJava8.displayStaticMethod();
	}
}

Output:

TestJava8InterfaceImpl : Implementing abstract method in this class

InterfaceInJava8 : static method impl inside Java Interface

5.1 Point to remember about static methods in interface:

  • These static methods will act as helper method
  • This makes easier for us to organize helper methods specific to interface rather to any separate class
  • This way, static methods are belong to interface rather to implementing classes
  • Cannot override these static methods

Related Articles:

References:

Happy Coding !!
Happy Learning !!

Java - Interview Question and Answers on Constructor
Java - Constructor in Interface, a tricky question post Java 8 release