Java 8 – Default Methods, inheritance

Default Methods

In the previous article we learned about functional programming using lambdas introduced in java8. We also learned about functional interfaces and method references. In this tutorial we will look at a side effect in Java8 – Default methods.

The designers in Java always strive for backward compatibility, and so to add methods to the Collection interface (which you will see in the next tutorial) would break builds in pre java8 compilers. To overcome that problem, the designers have come up with default methods. These are methods in an interface that have a default implementation. I know what you are thinking … that changes the definition of interface! yes, it does. Lets look at the default method added in the Collection interface

		default Stream<E> stream() {
        	return StreamSupport.stream(spliterator(), false);
    	}
		

Remember: Default methods in interfaces have a default implementation.

Default methods have been added to a lot of places and it would be useful to know how overriding works for them. Here are some of the rules for default method overriding:

Default methods – Inheritance

Let us look at how inheritance works in default methods. Lets say you have an interface with one default method

		public interface InterfaceA {
    		default void methodB() {
	   		  System.out.println("InterfaceA.methodB()");
    		}
		}
		

You can create a class that implements this interface

		class classA implements InterfaceA {}
		

The class does not have to implement the default method methodB.

		classA classA = new classA();
		classA.methodB(); // prints InterfaceA.methodB()
		

The class may choose to override the method

		class classA implements InterfaceA {
    		@Override
	    	public void methodB() {
				System.out.println("classA.methodB()");
				InterfaceA.super.methodB();
			}
		}
		

When we call the method from the class, the overridden method calls called.

		classA classA = new classA();
		classA.methodB(); 
		// prints 'classA.methodB()' followed by 'InterfaceA.methodB()'
		

Its time to start adding complexity. Lets create another interface with the same default method

		interface InterfaceB {
			default void methodB() {
				System.out.println("InterfaceB.methodB()");
			}
		}
		

Now we create a class that implements both InterfaceA and InterfaceB. The compiler now does not know which implementation of methodB it should use (should it use the implementation from InterfaceA or should it use the one from InterfaceB?). It cant decide, so we need to provide an implementation of methodB in the new class

		class ClassAB implements InterfaceA, InterfaceB {

			public void methodB() {
				System.out.println("classAB.methodB()");
				InterfaceA.super.methodB();
				InterfaceB.super.methodB();
			}

		}
		ClassAB classAB = new ClassAB();
		classAB.methodB();
		// prints
		// classAB.methodB()
		// InterfaceA.methodB()
		// InterfaceB.methodB()
		

Note that if you want the class to have the implementation from a particular interface then you just make a call to the methodB of that interface from methodB of the classAB.

Remember:If a class implements two interfaces that both have a default method with the same name then the class must provide an implementation of that method ot resolve ambiguity

However, the ambiguity is only for two interfaces. Lets say you create a class that implements interfaceA but does not provide an implementation for methodB

		class classA implements InterfaceA {
        }
		

We now create a class that extends ClassA and implements InterfaceB. We dont provide an implementation for methodB. The compiler does not complain. It knows that in case of an ambiguity a class takes precedence.

		class ClassA2 extends classA implements InterfaceA {
		}
		// we create the class and call methodB
		ClassA2 classA2 = new ClassA2();
		classA2.methodB();
		// prints InterfaceA.methodB()
		

Remember:If a dis-ambiguity arises in the default method with the same name method present in both a class and an interface, the class always wins

There is another useful trick that you can perform. You can ‘un-implement’ a default method in an implemented class if you declare the class abstract

		abstract class ClassA3 implements InterfaceA {
			public abstract void methodB();
		}
		

This completes our introduction to the default methods. Our next tutorial is probably the most interesting one, since it deals with yet another major change in Java8 – Streams. Stay tuned….

Leave a Comment