An interface is a fully abstract class used to specify the behavior of a class. A Java interface may contains static constants, default methods, static methods, nested tyoes and abstract methods (methods without a body). Method bodies exist only for default methods and static methods.
A class implements an interface, thereby inheriting the abstract methods of the interface. A class implementing an interface must define all methods of an interface unless implementing class is abstract.
Key Characteristics of Interfaces
- Abstract Methods : Interfaces can contain abstract methods that have no implementation. These methods are implicitly public and abstract.
- Constants : Interfaces can declare constants, which are implicitly public, static, and final. These constants can be used across classes that implement the interface.
- No Instance Variables : Interfaces cannot have instance variables. They can only have constants.
- No Constructors : Interfaces cannot have constructors since they cannot be instantiated
interface Shape { // Abstract methods. public int getArea(); public int getCurcumference(); }
Why do we need an Interface
- Similar to abstract classes, interfaces help us to achieve abstraction in Java. getArea() method calculates the area of a shape but the way area is calculated is different for different shapes. Hence, the implementation of getArea() is different for different shapes like square, rectangle etc.
- An Interfaces provide the blueprint of the implementing class. Any class implementing the interface must follow the blueprint of the interface. For example, any class implementing Shape interface must provide two public methods which returns area and circumference of a shape.
- Interfaces facilitate polymorphism, allowing objects of different classes to be treated as objects of a common type.
- By defining a set of methods in an interface, you create a contract that classes must adhere to. This promotes modularity and code reusability.
- Interfaces are also used to achieve multiple inheritance in Java. Since multiple inheritance is not allowed in Java, a class can implement multiple interfaces to achieve multiple inheritance.
In above example, we have created an interface named Shape. This interface contains two abstract methods getArea and getCurcumference. Any class implementing Shape interface must define the body of getArea and getCurcumference method.
Here is an example program to implement above mentioned Shape interface.
interface Shape { // Abstract methods. public int getArea(); public int getCircumference(); } class Square implements Shape { int side; Square(int side) { this.side = side; } public int getArea(){ return side * side; } public int getCircumference(){ return 4 * side; } } class Rectangle implements Shape { int length, width; Rectangle(int length, int width) { this.length = length; this.width = width; } public int getArea(){ return length * width; } public int getCircumference(){ return 2 * (length + width); } } public class JavaInterface { public static void main(String[] args) { // Create objects of Square and Rectangle class Square sq = new Square(10); Rectangle rec = new Rectangle(10, 20); // Print area of Shapes System.out.println("Area of Square: " + sq.getArea()); System.out.println("Area of Rectangle: " + rec.getArea()); // Print circumference of Shapes System.out.println("Circumference of Square: " + sq.getCircumference()); System.out.println("Circumference of Rectangle: " + rec.getCircumference()); } }Output
Area of Square: 100 Area of Rectangle: 200 Circumference of Square: 40 Circumference of Rectangle: 60
In above program, class Square and Rectangle implements Shape interface. The formulae for calculating area and circumference is different for Square and Rectangle. Hence, both these classes contains specific implementation of interface methods.
Implementing Multiple Interfaces
A class can also implement multiple interfaces in Java. Interfaces are also used to achieve multiple inheritance in Java. Since multiple inheritance is not allowed in Java, a class can implement multiple interfaces to achieve multiple inheritance. To implement multiple interfaces, keyword implements is used once followed by a list of comma-separated interfaces. For Example:
class A implements B, C { // Code }
Java program to implement multiple interfaces
interface Area { public int getArea(); } interface Circumference { public int getCircumference(); } class Square implements Area, Circumference { int side; Square(int side) { this.side = side; } public int getArea(){ return side * side; } public int getCircumference(){ return 4 * side; } } public class MultipleInterfaces { public static void main(String[] args) { Square sq = new Square(10); // Print area and circumference System.out.println("Area of Square: " + sq.getArea()); System.out.println("Area of Square: " + sq.getCircumference()); } }Output
Area of Square: 100 Area of Square: 40
In above program, class square is implementing both Area and Circumference imterface. In this case, Square class must implement all abstract methods of both interfaces.
Extending an Interface
An interface can extend another interface in the same way that a class can extend another class in java. The extends keyword is used to extend an interface, and the child interface inherits all methods of the parent interface. For Example:
interface A extends B { // members of A }
A class implementing child interface must implement all abstract methods of child as well as parent interface.
Java program to extend an interfaces
interface Eat { public void eat(); } interface Digest { public void digestFood(); } class Chicken implements Digest { public void eat() { System.out.println("Chicken is eating"); } public void digestFood() { System.out.println("Chicken is digesting food"); } } public class ExtendInterfaces { public static void main(String[] args) { Chicken chicken = new Chicken(); chicken.eat(); chicken.digestFood(); } }Output
Chicken is eating Chicken is digesting food
In above program, interface Digest extends interface Eat and class Chicken is implementing Digest interface. In this case, Chicken class must implement abstract methods of both Eat and Digest interfaces.
Default and Static Methods in Interfaces
- Default Methods : Starting from Java 8, interfaces can have default methods. A default method is a method with a default implementation that is provided in the interface itself. Classes that implement the interface can use the default implementation or override it if needed.
interface Printable { void print(); // Default method with implementation default void log(String message) { System.out.println("Logging: " + message); } }
In this example, the Printable interface has a default method log(). Classes implementing this interface can use the default implementation or provide their own. - Static Methods : Similarly, interfaces can have static methods, which are associated with the interface and not tied to any instance of the implementing class.
interface MathOperation { int add(int a, int b); // Static method in the interface static int subtract(int a, int b) { return a - b; } }
In this example, the MathOperation interface has a static method subtract(). This method can be called using the interface name, and it is not tied to any specific instance of a class.
- A class can implement an interface by using "implements" keyword.
- An interface can contain any number of methods.
- An interface cannot contain a constructor.
- We cannot create an object of interface directly.
- An interface can be empty, with no variables and methods definition.
- An interface can extend multiple interfaces.
- We cannot use final keyword in the interface definition, as it will result in a compiler error.
- All interface declarations must have public or default access modifier. The compiler will automatically add abstract modifier.
- An interface method cannot be final or protected.
- Interface methods do not have a body, the body is provided by the implementing class.
- Interface variables are public, static, and final by default. We cannot change their visibility.
Best Practices for Using Interfaces
- Name Interfaces with Adjectives or Nouns : Choose names for interfaces that reflect the behavior they represent. Names should be descriptive and convey the purpose of the interface, like Printable, Runable etc.
- Prefer Composition Over Multiple Inheritance : While Java allows a class to implement multiple interfaces, it's often more maintainable and less error-prone to prefer composition over multiple inheritance. Design classes to have a single responsibility and use interfaces to compose behavior.
- Keep Interfaces Cohesive : An interface should have a cohesive set of methods related to a specific concept or behavior. Avoid creating large interfaces that cover a wide range of unrelated functionalities.
- Document Your Interfaces : Document the purpose and usage of your interfaces. Clearly specify the contract that implementing classes must adhere to, including any preconditions and postconditions.
- Use Default Methods Judiciously : Default methods can provide a default implementation for interfaces, but use them judiciously. Overusing default methods might lead to classes unintentionally inheriting behavior that they should override.
Conclusion
Interfaces are a powerful feature in Java that enable the creation of flexible, modular, and maintainable code. Whether you're designing APIs, implementing design patterns, or leveraging the benefits of lambda expressions, understanding how to use interfaces effectively is crucial for Java developers. By grasping the concepts presented in this tutorial, you'll be well-equipped to harness the full potential of interfaces in your Java projects. Interfaces play a pivotal role in achieving abstraction, multiple inheritance, and creating extensible and polymorphic code, making them an indispensable tool in the Java developer's toolkit.