Skip to content

Interfaces in Java 8: The Default Method, with Examples

Learn how the default method in Java 8 interfaces works, how it lets you add behavior without touching your classes, and how it simulates multiple inheritance.

You can download the project for this post by clicking HERE.

In this post we are going to talk about a pretty interesting change that was added in Java 8: the "default" method of the new interfaces.

As we already mentioned in the posts where we talked about polymorphism, an "interface" is  a pure abstract class in which all of its methods are abstract and therefore cannot be implemented in the Interface class. Well, Java 8 now includes the "default" method, which can be implemented in the interface class, and whose implementation will be shared by all the classes that implement that interface. Put that way, you might think this method breaks the premise that interfaces are pure abstract classes, but adding this new method to Java 8 interfaces serves two interesting purposes:

  1. Not having to modify the classes that use that interface.
  2. Simulating a "Pseudo Multiple Inheritance", since Java doesn’t have multiple inheritance as such. We’ll come back to this point later to clarify the concept of pseudo multiple inheritance.

Point 1 (although it may sound hacky) makes quite a lot of sense, especially today, when responding quickly to change is very important. Imagine we have developed an interface that 20 classes implement, and at the last minute we need to add a new feature that all the classes implementing our interface must have. In this case, implementing a "default" method in the interface would solve the problem and let us adapt quickly to the change. This would be a quick fix, although if we were purists, with more time we should rewrite those methods in the classes that implement the interface.

To see this, we are going to give a quick fix to the example from the post "Polymorphism in Java -Interface- (Part II), with examples", in which we simulated the behavior of the Spanish national football team. In that example we implemented the behavior shown in the following class diagram:

Interface_java_jarroba

As you can see, we have three classes that implement the same interface, but now we want to add 2 new behaviors common to all 3 classes that implement the interface: giving a press conference (ruedaPrensa()) and making a promotional video (videoPublicitario()). To do that, we create these two methods in the interface and implement them there, leaving the class diagram like this:

interface_default_static_jarroba

In code, the interface would be implemented like this:


public interface IntegranteSeleccionFutbol {

	void concentrarse();

	void viajar();

	void entrenar();

	void jugarPartido();
	
	default void ruedaPrensa(){
		System.out.println(" da una rueda de prensa (desde la Interface)");
	}
	
	default void videoPublicitario (){
		System.out.println(" hacer un video publicitario (desde la Interface)");
	}

}

In the MAIN method we create one object of each class and run the methods implemented in the interface like this:


// ArrayList of SeleccionFutbol objects, regardless of the child class the object belongs to
public static ArrayList integrantes = new ArrayList();

public static void main(String[] args) {

	SeleccionFutbol delBosque = new Entrenador(1, "Vicente", "Del Bosque", 60, 28489);
	SeleccionFutbol iniesta = new Futbolista(2, "Andres", "Iniesta", 29, 6, "Interior Derecho");
	SeleccionFutbol raulMartinez = new Masajista(3, "Raúl", "Martinez", 41, "Licenciado en Fisioterapia", 18);

	integrantes.add(delBosque);
	integrantes.add(iniesta);
	integrantes.add(raulMartinez);

	// PRESS CONFERENCE WITH THE DEFAULT METHOD
	System.out.println("Todos los integrantes dan una rueda de prensa. (Todos ejecutan el mismo método)");
	for (SeleccionFutbol integrante : integrantes) {
		System.out.print(integrante.getNombre() + " " + integrante.getApellidos() + " -> ");
		integrante.ruedaPrensa();
	}
		
	// PROMOTIONAL VIDEO WITH THE DEFAULT METHOD
	System.out.println("Todos los integrantes graban un video publicitario. (Todos ejecutan el mismo método)");
	for (SeleccionFutbol integrante : integrantes) {
		System.out.print(integrante.getNombre() + " " + integrante.getApellidos() + " -> ");
		integrante.videoPublicitario();
	}

      ...................................

}

The output of running this code fragment is the behavior implemented in the interface class:


Todos los integrantes dan una rueda de prensa. (Todos ejecutan el mismo método)
Vicente Del Bosque ->  da una rueda de prensa (desde la Interface)
Andres Iniesta ->  da una rueda de prensa (desde la Interface)
Raúl Martinez ->  da una rueda de prensa (desde la Interface)

Todos los integrantes graban un video publicitario. (Todos ejecutan el mismo método)
Vicente Del Bosque ->  hacer un video publicitario (desde la Interface)
Andres Iniesta ->  hacer un video publicitario (desde la Interface)
Raúl Martinez ->  hacer un video publicitario (desde la Interface)

As you can see, we were able to implement a new behavior from an interface and make it available in every class that implements that interface.

On the other hand, we said that with the new Java 8 interfaces we can simulate a "Pseudo Multiple Inheritance". That said, we need to clarify these words a bit. We know that inheritance "automatically shares the attributes and methods of the parent class with the child classes". We also know that Java doesn’t support multiple inheritance, since it only lets you inherit methods and attributes from a single class; that is, it has only one parent class. With the new Java 8 interfaces, we can make a class implement as many interfaces as we want, and since interfaces can have "default" methods, every class that implements that interface will have those methods, and they won’t need to be overridden. In other words, with Java 8 interfaces we can have multiple inheritance applied exclusively to methods, but not to attributes.

In the Java 8 project we shared at the beginning, we implemented an example to see this pseudo multiple inheritance. Take a look at the following class diagram, where we have two interfaces called "DeportistaInterface" and "IntegranteInterface", each with two "default" methods. We can see that "FutbolistaHM" and "EntrenadorHM" implement both interfaces, so they will have the "default" methods of both interfaces; in other words, it’s as if they inherited the methods from the interface. On the other hand, the "MasajistaHM" class only implements the "IntegranteInterface" interface, so it only "inherits" the "default" methods from that one. In short, we have simulated inheritance of methods, but not of attributes, which we have "inherited" from the interface class.

interface_java8_seudo_herencia_multiple_jarroba

Next, let’s see how we implemented the interfaces:


public interface IntegranteInterface {

    default void concentrarse() {
	System.out.println("Concentrarse (Interface IntegranteInterface)");
    }

    default void viajar() {
	System.out.println("Viajar (Interface IntegranteInterface)");
    }

}

public interface DeportistaInterface {

    default void entrenar() {
	System.out.println("Entrenar (Interface DeportistaInterface)");
    }

    default void jugarPartido() {
	System.out.println("Jugar Partido (Interface DeportistaInterface)");
    }
}

As you can see, in the default methods we implemented a behavior that the classes implementing that interface will "inherit". Next we show the implementation of the "FutbolistaHM", "EntrenadorHM" and "MasajistaHM" classes:


public class FutbolistaHM extends SeleccionFutbolHM 
implements DeportistaInterface, 
IntegranteInterface {

	private int dorsal;
	private String demarcacion;

	// constructor, getter and setter
}
    

public class EntrenadorHM extends SeleccionFutbolHM 
implements DeportistaInterface, 
IntegranteInterface {

	private int idFederacion;

        // constructor, getter and setter
}

public class MasajistaHM extends SeleccionFutbolHM 
implements IntegranteInterface {

	private String titulacion;
	private int aniosExperiencia;

        // constructor, getter and setter

}

As you can see, each class implements the interface it needs. Now let’s see how each of these classes runs the interface methods with the following code fragment written in the MAIN method:


// ArrayList of SeleccionFutbol objects, regardless of the child class
// the object belongs to
public static ArrayList integrantes = new ArrayList();

public static void main(String[] args) {

	SeleccionFutbolHM delBosque = new EntrenadorHM(1, "Vicente", "Del Bosque", 60, 28489);
	SeleccionFutbolHM iniesta = new FutbolistaHM(2, "Andres", "Iniesta", 29, 6, "Interior Derecho");
	SeleccionFutbolHM raulMartinez = new MasajistaHM(3, "Raúl", "Martinez", 41, "Licenciado en Fisioterapia", 18);

	integrantes.add(delBosque);
	integrantes.add(iniesta);
	integrantes.add(raulMartinez);
		
	// TRAVEL
	System.out.println("Todos los integrantes viajan para jugar un partido. (Todos ejecutan el mismo método)");
	for (SeleccionFutbolHM integrante : integrantes) {
		System.out.print(integrante.getNombre() + " " + integrante.getApellidos() + " -> ");
		((IntegranteInterface) integrante).viajar();
	}
	
	// TRAIN
	System.out.println("nSolo Del Bosque e Iniesta entrenan ya que el masajista no tienen el método entrenar");
	System.out.print(delBosque.getNombre() + " " + delBosque.getApellidos() + " -> ");
	((DeportistaInterface) delBosque).entrenar();
	System.out.print(iniesta.getNombre() + " " + iniesta.getApellidos() + " -> ");
	((DeportistaInterface) iniesta).entrenar();		
}

In this code fragment we can see that all of them are able to run the "viajar()" method of the "IntegrantesInterface" interface, since they all implement that interface, and only objects of the "FutbolistaHM" and "EntrenadorHM" classes can run the "entrenar()" method of the "DeportistaInterface" interface. The result of this code is the following:


Todos los integrantes viajan para jugar un partido. (Todos ejecutan el mismo método)
Vicente Del Bosque -> Viajar (Interface IntegranteInterface)
Andres Iniesta -> Viajar (Interface IntegranteInterface)
Raúl Martinez -> Viajar (Interface IntegranteInterface)

Solo Del Bosque e Iniesta entrenan ya que el masajista no tienen el método entrenar
Vicente Del Bosque -> Entrenar (Interface DeportistaInterface)
Andres Iniesta -> Entrenar (Interface DeportistaInterface)

This is, in short, what the new Java 8 interfaces let us do: they make us a bit more agile when making last-minute changes and let us sort of simulate multiple inheritance.

“Interfaces in Java 8: The Default Method, with Examples” by Ricardo Moya at jarroba.com, licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0. Registered at Safe Creative.

Ricardo Moya

I work in Machine Learning and Big Data. I like learning new technologies and explaining them as clearly as I can on this site.

You may also like

Inheritance in Java, with Examples

Learn what inheritance is in object-oriented programming and how it works in Java, using extends, protected and super with a clear, practical example.

Apr 8, 2014

Comments

Leave a comment


This site uses Akismet to reduce spam. Learn how your comment data is processed.