Java Interface Tutorial

186 views

In this article, we’ll go through what an interface is in Java, why you should use it and when you should use an interface.

1. What Is a Java Interface?

An interface in Java is like an abstract class, but it provides full abstraction as you mainly do not implement methods (although since Java 8 you can). Additionally, it provides information to a developer regarding the API methods that this interface includes. For example, if you check the List interface, you will see all the methods that you can call when using a class that implements this interface; one of these classes is ArrayList.

Interfaces in Java have the following characteristics:

  • All methods are effectively public so you can skip adding the public access modifier.
  • All members are effectively public static final and you can omit adding these keywords.
  • Methods can be one of the following types:
    • abstract
    • static
    • default
  • Unlike classes in Java, an interface can extend multiple interfaces.
  • A class can implement multiple interfaces.
  • In order to use an interface, you should have a class that implement this interface, by using the implements keyword.
  • You cannot create any object since an interface cannot have a constructor.
  • You can define nested interfaces, either inside classes or inside interfaces

1.1 Abstract Methods

An abstract method is a method that only has its signature and no implementation.

The purpose of abstract methods is to implement them in any class that implements this interface. Of course, if you’d like this class to not implement this method, you must declare this class as abstract.

The formula for declaring an abstract method in an interface is the following:

void_or_return_type method_name (param_1, param_2, ..., param_n)

As we already stated, you could add public abstract keywords but there is no need as they will be added implicitly.

1.2 Static Methods

Static methods were added in Java 8, in order to provide the ability to implement helper methods inside an interface. Since they are static we cannot override and in order to use them, you must use the interface name.

The formula for defining a static method in an interface is the following:

static void_or_return_type method_name(param_1, param_2, ... , param_n)

To call a static method you should write the following:

Interface_name.method_name(param_1, param_2, ..., param_n)

1.3 Default Methods

Default methods were also added on Java 8, in order to allow us to create default behavior inside interfaces. Also, unlike an abstract method, you can skip implementing a default method in a class that implements this interface.

Note that, unlike static methods, you can override default methods.

To define a default method, the formula is the following:

default void_or_return_type method_name(param_1, param_2, ..., param_n)

2. Simple Interface Example

In this section, we’ll go through a simple interface example and see how an interface would work in action.

2.1 Defining an Interface

For this example we have created the following interface:

public interface SimpleInterface {

    int NUMBER_OF_TIMES = 5;

    void printHelloInLanguage(String language);

    default void sayHello(){
        System.out.println("Hello world");
    }

    static void sayBye(){
        System.out.println("Bye world");
    }

    static void sayByeMultipletimes(){
        for (int i = 0; i <NUMBER_OF_TIMES ; i++) {
            sayBye();
        }

    }

}
  • Line 3: We added a member which is effectively a constant.
  • Line 5: Concerning the methods, we have defined an abstract method which will be implemented by classes that implement this interface.
  • Line 6: We have created a default method which you have the ability to override.
  • Line 11: Then, we have created a static method. This method cannot be overriden.
  • Line 15: We have created another static method which calls the sayBye() method multiple times. We cannot use the sayHello() method since it is not static.

2.2 Defining a Class the implements This Interface

Now we continue with the creation of a class that implements this interface:

public class SimpleInterfaceImpl implements SimpleInterface{

    @Override
    public void printHelloInLanguage(String language) {
        switch (language){
            case "english":
                System.out.println("Hello");
                break;
            case "greek":
                System.out.println("Γειά");
                break;
        }
    }

    @Override
    public void sayHello() {
        SimpleInterface.super.sayHello();
        System.out.println("Hi again");
    }
  • Line 3: We use @Override annotation to inform the complier that we intend to override this method.
  • Line 4-13: We implement the previously defined abstract method. If we had decided not to implement it, we should have defined the class as abstract.
  • Line 16: We override the sayHello() method which was a default method. Note that we could skip overriding this method and the code would compile without any problem.
  • Line 17: We call the default method already defined in the interface.
  • Line 18: We add additional code to this method, otherwise it wouldn’t make any sense to override it.

2.3 Calling Interface and Class Methods

Now we can take a look at how interface and classes work in action:

SimpleInterface simpleInterface = new SimpleInterfaceImpl();

System.out.println("calling sayHello():");
simpleInterface.sayHello();
System.out.println();

System.out.println("calling printHelloInLanguage():");
simpleInterface.printHelloInLanguage("english");
System.out.println();


System.out.println("calling sayBye():");
SimpleInterface.sayBye();
System.out.println();

System.out.println("calling sayByeMultipletimes():");
SimpleInterface.sayByeMultipletimes()

This will print:

calling sayHello():
Hello world
Default method overriden!

calling printHelloInLanguage():
Hello

calling sayBye():
Bye world

calling sayByeMultipletimes():
Bye world
Bye world
Bye world
Bye world
Bye world

3. Real-World Interface Example

For this example, we have created 1 interface and 2 classes that implement this interface.

3.1 The Drivable Interface

The name of this interface is Drivable and provides the ability to add behavior for every class (a type of vehicle) that implements it.

public interface Drivable {

    default void canBeDrivenOn(){
       System.out.println("Default is road");
    }

    void printNumberOfWheels();

    void printTypeOfFuel();

    static void sayHelloFrom(String type){
       System.out.println("Hello, I'm inside a(n) "+type);
    }
}

Here we have defined a default method, to have a fallback in case the canBeDrivenOn() method is not overridden by the class in question. Then we added 2 abstract methods and finally, a static method that takes the type of vehicle as a parameter and prints it.

3.2 The Car Class

public class Car implements Drivable{

    private String color;

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public void printNumberOfWheels() {
        System.out.println("Car has 4 wheels");
    }

    @Override
    public void printTypeOfFuel() {
        System.out.println("Car mainly uses Gas");
    }

    public void printColor(){
        System.out.println("The color of the car is "+color); 
    }
}

As you can observe, this class implements the Drivable interface. It overrides the printNumberOfWheels() and printTypeOfFuel() methods and also contains a method that is only defined and implemented in the Car class, the printColor() method.

Let’s try to see how this class would work in action!

If we create a car using the following code

Drivable car = new Car();

The only methods that you can use are the ones that you have declared or implemented in the Drivable interface, so the following will not compile:

car.setColor("red");
car.printColor();

This happens because the type of the object dictates which methods you can call and not the reference to the object.

In order to use the setColor() and printColor(), we need to instantiate the car as follows:

Car car =  new Car();

Of course, when using Drivable as the type of object, we can call the following methods:

car.printNumberOfWheels();
car.printTypeOfFuel();
car.canBeDrivenOn();
Drivable.sayHelloFrom("car");

And this snippet will print:

Car has 4 wheels
Car mainly uses Gas
Default is road
Hello, I'm inside a(n) car

Note that since we did not override the canBeDrivenOn() method, the default was used.

3.3 The Boat Class

public class Boat implements Drivable{

    @Override
    public void printNumberOfWheels() {
        System.out.println("A boat has no wheels");
    }

    @Override
    public void printTypeOfFuel() {
        System.out.println("Boat mainly uses gas and diesel");
    }

    @Override
    public void canBeDrivenOn() {
        System.out.println("Sea");
    }

    public static void main(String[] args) {

    }

}

As you can see by yourself, there are 2 differences with the Car class (other than the different implementations of default methods).

The first difference is that we do not have to worry about restricting this class if we instantiate it using the Drivable interface as type, since it does not have any members or methods.

The second difference is that here we have overridden the default method canBeDrivenOn() in order to print the correct value.

So, if we run the following:

Drivable boat = new Boat();
boat.printNumberOfWheels();
boat.printTypeOfFuel();
boat.canBeDrivenOn()

It will print:

A boat has no wheels
Boat mainly uses gas and diesel
Sea

4. Conclusion

By now you should be able to know what interfaces are and why they are used in Java. You can find the source code on our GitHub page.

5. Sources

[1]: Interfaces – Oracle

Related Posts