Java 8 – default and static methods

In this article, we will discuss default and static methods that can be added to Interface from Java 1.8 version

Quick background about Java Interface

Prior to Java 1.8 version, Interface can contain only 2 things

  1. abstract methods, by default all methods are public & abstract even if it is not declared explicitly
  2. variables which are by default public, static and final

Note:

  • whether you declare public/abstract and public/static/final modifiers or NOT to methods and variables respectively, by default these modifiers gets added to interface after compilation
  • quick trick to verify whether above mentioned modifiers gets added or not, first declare variables and methods without any modifiers and then check after de-compiling java class file
  • You will notice those modifiers are added by compiler after compilation

Interface in Java 1.7 version

package net.bench.resources.java7;

public interface DemoInterfaceInJava7 {

	// 4 methods
	void method1();
	public void method2();
	abstract void method3();
	public abstract void method4();

	// any class that implements this interface has
	// to provide implementation for all 4 methods
}
  • Till Java 1.7 version, interface contains methods which are by default abstract and public so that it can be overridden using Java inheritance concept
  • Full interface implementation : Any class that implements above defined interface, has to provide implementation for all 4 abstract methods
  • Partial interface implementation : Also, we can provide partial implementation but class has to be declared abstract class. So that further extending class has to provide implementation compulsorily for remaining methods

Challenges faced with Interface till Java 1.7 version

  • Suppose, above interface is implemented by 100s of classes which provides implementation for all 4 abstract methods
  • Now, if we want to add one more abstract method to existing interface for our application design/functionality requirements
  • Then, compulsorily we have touch upon other 100s of classes and provide implementation for 5th abstract method in each and every class

1. default method

To overcome above challenges, Oracle/Sun introduced new features in Java 1.8 version i.e.; default method

  • The challenges we have listed above, can be eliminated by defining default method instead of 5th abstract method
  • By declaring default method, we have maintained class-interface relationship well and need not necessarily touch upon existing 100s of classes for implementing 5th abstract method
  • Because defining default method means we have provided base implementation which could be generic
  • And wherever required, we can override this default method and provide more specific implementation
  • This way, we can overcome interface-class relationship without breaking any contracts between them
package net.bench.resources.java8;

public interface DemoInterfaceInJava8 {

	// 4 methods
	void method1();
	public void method2();
	abstract void method3();
	public abstract void method4();

	// default
	default void display() {
		System.out.println("declarind/defining default method");
	}
}

class Demo implements DemoInterfaceInJava8 {

	@Override
	public void method1() {
		// TODO Auto-generated method stub
	}

	@Override
	public void method2() {
		// TODO Auto-generated method stub
	}

	@Override
	public void method3() {
		// TODO Auto-generated method stub
	}

	@Override
	public void method4() {
		// TODO Auto-generated method stub
	}
}
  • In the above example, we haven’t overridden default method and compiler doesn’t throw any compilation error
  • But if we want to provide more specific implementation then we can override default method
  • See below example where we have specific implementation for default method
class Demo implements DemoInterfaceInJava8 {

	public void display() {
		System.out.println("Overriding and providing more specific implementation");
	}

	@Override
	public void method1() {
		// TODO Auto-generated method stub
	}

	@Override
	public void method2() {
		// TODO Auto-generated method stub
	}

	@Override
	public void method3() {
		// TODO Auto-generated method stub
	}

	@Override
	public void method4() {
		// TODO Auto-generated method stub
	}
}

1.1 Important rules w.r.t default method

  • Definition for default method in Interface in Java 1.8 version is more generic and this is available to all extending classes (inheritance concept)
  • default method name can contain any valid java identifier but it shouldn’t clash with any name from Object class‘ method like hashCode();
  • Otherwise compiler throws error stating “A default method cannot override a method from java.lang.Object

But even with all this, there is one age old problem we have been facing in earlier java versions and now has been addressed in Java 1.8 version i.e.; diamond problem or ambiguity problem using super keyword

1.2 Multiple inheritance w.r.t Interface in Java 1.8

  • If we define 2 interfaces and both contains default methods with exactly same signature, then if class that implements these interfaces will result into ambiguity problem or diamond problem, although it is valid/allowed
  • Because implementing class doesn’t understand which version of default method to be invoked
  • Let us see example along with compile-time error and later we will look how it has been addressed in Java 1.8 version
package net.bench.resources.java8;

interface SuperInterfaceA {

	public default void print() {
		System.out.println("Hello World in Parent Interface A");
	}
}

interface SuperInterfaceB {

	public default void print() {
		System.out.println("Hello World in Parent Interface B");
	}
}

public class DemoClass implements SuperInterfaceA, SuperInterfaceB {

}

Compile-time error : Duplicate default methods named print with the parameters () and () are inherited from the types SuperInterfaceB and SuperInterfaceA

1.3 Solution for Ambiguity or diamond problem

The solution to above problem is, we have to override default method and need not necessarily provide implementation. So, you can

  1. override default method and invoke implementation of 1st interface’s default method using super keyword i.e.; SuperInterfaceA.super.print();
  2. Similarly, override default method and invoke implementation of 2nd interface’s default method using super keyword i.e.; SuperInterfaceB.super.print();
  3. Or else override default method and provide more specific implementation
  4. In below case, we have invoked Super interface A’s default method
package net.bench.resources.java8;

interface SuperInterfaceA {

	public default void print() {
		System.out.println("Hello World in Parent Interface A");
	}
}

interface SuperInterfaceB {

	public default void print() {
		System.out.println("Hello World in Parent Interface B");
	}
}

public class DemoClass implements SuperInterfaceA, SuperInterfaceB {

	@Override
	public void print() {
		// invoking SuperInterfaceA's default method
		SuperInterfaceA.super.print();
	}
}

2. static method

Another important feature that is introduced in Java 1.8 version is static method in interface which is basically to overcome memory issues with classes

  • static keyword isn’t attached to any specific object/instance
  • Rather it is class-level concept adding memory overhead to class
  • And it is invoked with <ClassName>.<staticMethod> rather after creating objects which we usually do after instantiating objects for instance methods
  • If we want to define only static methods inside class for some utility purpose then it is better to define inside interface to overcome memory overhead and maintenance
  • Note: main() method from where Java class execution starts is also valid to define inside interface and it can also be executed, as we generally do with classes
package net.bench.resources.java8;

public interface StaticMethodExampleInJava8 {

	// normal abstract method
	public abstract void print();

	// default method
	public default void display() {
		System.out.println("Hello World inside default method");
	}

	// static method
	public static void show() {
		System.out.println("Hello World inside static method");
	}
}

2.1 static method w.r.t inheritance

  • If a class inherit interface, then overriding concept w.r.t static method is not allowed
  • Also, if we re-declare same static method signature in the implementing/extending/inheriting class, then this isn’t overriding rather method hiding concept
  • while invoking static method declared in interface we have use interface name like <InterfaceName>.<staticMethod> compulsorily
  • Note: using implementing/inheriting class name for calling/invoking static method defined in interface results into compilation error stating “The method show() is undefined for the type Test
  • Only allowed way to invoke static method inside interface is <InterfaceName>.<staticMethod> and if we try to call/invoke using any other way then it will result into compile-time error as stated above point
package net.bench.resources.java8;

public interface StaticMethodExampleInJava8 {

	// default method
	public default void display() {
		System.out.println("Hello World inside default method");
	}

	// static method
	public static void show() {
		System.out.println("Hello World inside static method");
	}
}

class Test implements StaticMethodExampleInJava8 {

	public static void main(String[] args) {

		// calling static method
		StaticMethodExampleInJava8.show();
	}
}

References:

Happy Coding !!
Happy Learning !!

Java 8 - Pre-defined Functional interface
Java 8 - Anonymous Inner class v/s Lambda Expression