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 fields are effectively
public static final
and you can omit adding these keywords. - Methods can be one of the following types:
abstract
static
default
- With regard to the access modifier of a method, since Java 9, we can have
private
methods inside an interface. Theseprivate
methods can be either static or non-static. - 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 implements 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 Java 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 thesayBye()
method multiple times. We cannot use thesayHello()
method since it is notstatic
.
2.2 Defining a Class that 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 Java 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. Java Interface vs Abstract Class
Below you can find a comparison table between an abstract class and an interface:
Abstract Class | Interface |
---|---|
Members can have any access modifier, they can be static or non-static and they can be final or non-final | Members can only be public static final(constants) |
An abstract class can have many constructors | An interface cannot have any constructors |
Non-static concrete methods can have any access modifier | Non-static concrete methods can have the private access modifier only |
Static concrete methods can have any access modifier | Static concrete methods can only be private or public |
You cannot create default methods | You can create default methods |
You need to explicitly write the abstract keyword to declare an abstract method. | All methods that do not have any access modifier and are not static, are considered as public abstract by default. |
A subclass can only extend one abstract class | A subclass can implement multiple interfaces |
To extend an abstrac class you use the extends keyword | To implement an interface you use the implements keyword |
It is intended to provide partial abstraction | It is intended to provide full abstraction |
5. Conclusion
By now you should be able to know what interfaces are and why they are used in Java. Should you like to learn more about abstract classes, you can read this article. Finally, you can find the source code on our GitHub page.
6. Sources
[1]: Interfaces – Oracle