In Java, an interface serves as a blueprint for a set of methods that a class needs to adhere to. Interfaces are valuable for enabling abstraction and facilitating multiple inheritance. Throughout this section, we will delve into the process of defining interfaces, exploring how abstraction and multiple inheritance can be realized through their implementation.
What is Interface in Java?
An interface serves as a design plan for a class that holds unchangeable constants and undefined methods. The purpose of interfaces is to achieve abstraction by including solely abstract methods (methods without implementation) and variables. It cannot be initialized, akin to an abstract class, and signifies an IS-A connection.
Starting from Java 8, interfaces have the capability to incorporate default and static methods. As of Java 9, interfaces are also able to encompass private methods.
Why Use an Interface in Java?
An interface is used in Java for the following reasons:
- To achieve abstraction by defining method signatures without implementation.
- To support multiple inheritance , as a class can implement multiple interfaces.
- To achieve loose coupling , making the code more flexible and easier to maintain.
Declaring an Interface
To declare an interface, the keyword interface is used. Interfaces offer full abstraction, implying that all methods are inherently abstract, while all fields are automatically public, static, and final. Any class that implements an interface is obligated to furnish implementations for all the methods specified within the interface.
Syntax of Interface Declaration
Here is the syntax to declare an interface:
interface <interface_name> {
// declare constant fields
// declare abstract methods
}
Example of Declaring an Interface
Here is an example to declare an interface:
interface Animal {
void eat();
void sleep();
}
In this illustration, the Animal interface defines two functions: eat and sleep. Every class that adheres to the Animal interface needs to furnish specific implementations for these functions.
Implicit Modifiers Added by the Java Compiler
When working with a Java interface, the compiler automatically includes specific modifiers for its members. Without explicitly being mentioned, all methods are inherently public and abstract. Likewise, any fields defined within an interface are automatically public, static, and final.
Put differently, interface methods are inherently public and abstract, whereas interface fields are inherently public, static, and final.
Starting from Java 8 onwards, interfaces have the ability to contain default and static methods, as elaborated on in subsequent sections of this chapter.
Relationship Between Classes and Interfaces
In the illustration below, it is demonstrated that a class can extend another class, an interface can extend another interface, and a class can implement an interface. This association establishes the way classes and interfaces collaborate to facilitate inheritance and abstraction within Java.
Interface Examples
To gain a better understanding of how interfaces are defined, executed, and utilized in Java, work through the provided instances below.
Example 1: Printable Interface
An illustration below demonstrates an interface containing a solitary method, which is then implemented by a class.
Example
//Creating an interface
interface Printable{
void print();
}
//Creating a class that implements Printable
class Printer implements Printable{
public void print(){System.out.println("Hello");}
}
//Creating a class that creates objects and call methods
public class Main{
public static void main(String args[]){
Printable p=new Printer();
p.print();
}
}
Output:
Example 2: Drawable Interface
The upcoming illustration showcases the implementation of a single interface by multiple classes. Typically, one entity defines the interface, and various classes offer their unique implementations. These implementation specifics are concealed from the end user.
Example
//Creating an interface
interface Drawable{
void draw();
}
//Implementation of Interface
class Rectangle implements Drawable{
public void draw(){System.out.println("drawing rectangle");}
}
class Circle implements Drawable{
public void draw(){System.out.println("drawing circle");}
}
//Using interface
public class Main{
public static void main(String args[]){
Drawable d=new Circle();//In real scenario, object is provided by method e.g. getDrawable()
d.draw();
}
}
Output:
drawing circle
Example 3: Bank Interface
The following demonstration illustrates the utilization of an interface to establish a uniform framework for interconnected classes. Every bank class offers a distinct implementation of the methods defined within the interface.
Example
interface Bank{
float rateOfInterest();
}
class SBI implements Bank{
public float rateOfInterest(){return 9.15f;}
}
class PNB implements Bank{
public float rateOfInterest(){return 9.7f;}
}
class HDFC implements Bank{
public float rateOfInterest(){return 8.7f;}
}
public class Main{
public static void main(String[] args){
Bank b;
b=new SBI();
System.out.println("SBI ROI: "+b.rateOfInterest());
b=new PNB();
System.out.println("PNB ROI: "+b.rateOfInterest());
b=new HDFC();
System.out.println("HDFC ROI: "+b.rateOfInterest());
}
}
Output:
SBI ROI: 9.15
PNB ROI: 9.7
HDFC ROI: 8.7
Implementing Multiple Inheritance Using Interfaces
The concept of multiple inheritance occurs when a class implements several interfaces or when an interface extends multiple interfaces.
Put differently, multiple inheritance is achieved by permitting a class to implement numerous interfaces or by allowing an interface to extend multiple interfaces.
Example
Below is an illustration showcasing how a class can utilize multiple interfaces in order to accomplish multiple inheritance.
//Creating two interfaces
interface Printable{
void print();
}
interface Showable{
void show();
}
//Creating a class that implements two interfaces
class Computer implements Printable,Showable{
public void print(){System.out.println("printing data...");}
public void show(){System.out.println("showing data...");}
}
//Creating a Main class to create object and call methods
public class Main{
public static void main(String args[]){
Computer c = new Computer();
c.print();
c.show();
}
}
Output:
printing data...
showing data...
Inheritance of Interfaces
In object-oriented programming, a class can realize an interface, while an interface can expand another interface. By extending an interface, it acquires all the abstract methods defined in the parent interface.
Any class that chooses to implement the child interface is required to supply concrete implementations for all methods specified in both the parent and child interfaces.
Example
The illustration below showcases the concept of interface inheritance, where one interface inherits from another interface. It also shows how a class can implement the derived interface by defining implementations for all the inherited methods.
interface Printable{
void print();
}
interface Showable extends Printable{
void show();
}
class Main implements Showable{
public void print(){System.out.println("Hello");}
public void show(){System.out.println("Welcome");}
public static void main(String args[]){
Main obj = new Main();
obj.print();
obj.show();
}
}
Output:
Hello
Welcome
Interfaces and Polymorphism
Interfaces offer a key advantage by enabling polymorphism. They enable an interface reference to be directed to any object of a class that implements the interface. Consequently, this grants the program the flexibility to determine during runtime which method implementation to utilize.
Example
The subsequent illustration showcases the concept of an interface reference being able to indicate an object of a class that enforces it, displaying polymorphic characteristics.
// Interface
interface Animal {
void eat();
void sleep();
}
// Implementation class
class Dog implements Animal {
public void eat() {
System.out.println("Dog is eating");
}
public void sleep() {
System.out.println("Dog is sleeping");
}
}
// Main class
public class Main {
public static void main(String[] args) {
// Interface reference pointing to Dog object
Animal myAnimal = new Dog();
myAnimal.eat();
myAnimal.sleep();
}
}
Output:
Dog is eating
Dog is sleeping
In this instance, the variable myAnimal represents an interface of type Animal and points to an instance of a Dog. It showcases polymorphism, where method invocations are determined during runtime depending on the specific object type.
Java 8 Default Method in Interface
Starting from Java 8, it is possible to include a method body within an interface by marking it as a default method. Let's examine this with an illustration:
Example
interface Drawable{
void draw();
default void msg(){System.out.println("default method");}
}
class Rectangle implements Drawable{
public void draw(){System.out.println("drawing rectangle");}
}
public class Main{
public static void main(String args[]){
Drawable d=new Rectangle();
d.draw();
d.msg();
}
}
Output:
drawing rectangle
default method
Java 8 Static Method in Interface
Starting from Java 8, it became possible to include static methods within interfaces. An illustration of this is shown below:
Example
interface Drawable{
void draw();
static int cube(int x){return x*x*x;}
}
class Rectangle implements Drawable{
public void draw(){System.out.println("drawing rectangle");}
}
class Main{
public static void main(String args[]){
Drawable d=new Rectangle();
d.draw();
System.out.println(Drawable.cube(3));
}}
Output:
drawing rectangle
27
Nested Interface
It is possible to define an interface within another interface, which are referred to as nested interfaces. Depending on the specific need, a class can choose to implement either the outer interface, the nested interface, or both.
Example
The forthcoming illustration showcases the process of declaring and executing a nested interface:
// Outer interface
interface Printable {
void print();
// Nested interface
interface MessagePrintable {
void msg();
}
}
// Class implementing the outer interface
class Printer implements Printable {
public void print() {
System.out.println("Printing document...");
}
}
// Class implementing the nested interface
class MessagePrinter implements Printable.MessagePrintable {
public void msg() {
System.out.println("Printing message...");
}
}
// Main class to test the implementation
public class Main {
public static void main(String[] args) {
Printable p = new Printer();
p.print();
Printable.MessagePrintable mp = new MessagePrinter();
mp.msg();
}
}
Output:
Printing document...
Printing message...
Interface Vs. Abstract Class
A concept class is capable of containing both abstract and tangible methods, constructors, and various variable types, though it does not enable multiple inheritance. Conversely, an interface is restricted to declaring abstract methods exclusively (with the inclusion of default and static methods permitted since Java 8), lacks constructors, and facilitates multiple inheritance.
Explore further information on the variances between abstract classes and interfaces in this article: Java - Abstract Classes Versus Interfaces.