In Java, abstract classes and interfaces are important components because they help us implement a key idea in Object-Oriented Programming called Abstraction.
Even though both abstract classes and interfaces are used for Abstraction, they have differences and cannot be used interchangeably. In this discussion, we will compare abstract classes and interfaces using real-life examples. We will also explore when it is appropriate to use interfaces and abstract classes.
Before Directly jumping into the difference, let’s go through with the basic understanding of Interface vs Abstract Class. So this will help you understand the difference between Abstract Class and Interface Easily.
What is Abstract Class In Java?
An abstract class is a special kind of class that is declared using the keyword “abstract.” It has a combination of abstract methods (methods without a body) and concrete methods (methods with a body), which sets it apart from a regular class. Unlike a normal class, an abstract class cannot be directly used to create an object. However, we can create references to an abstract class by creating another class that extends the abstract class and provides implementations for its methods.
When we create an object of the child class that extends the abstract class, we can use that object to call both abstract and normal methods defined in the abstract class. An abstract class can also have constructors, and they are invoked when an instance of the inherited class is created.
In Java, it is possible to have an abstract class without explicitly using the “abstract” keyword. However, such classes cannot be instantiated directly; they can only be inherited. Additionally, these classes can have final methods which cannot be overridden in the child classes.
For More details about Abstract Class, you can visit this link.
What Is Interface In Java?
An interface in Java is similar to a class but with some key differences. It can have methods and variables just like a class, but the methods declared in an interface are abstract by default. This means they do not have a body and need to be implemented by a class before they can be used.
Interfaces provide full abstraction, ensuring that the methods within them are implemented by the class that implements the interface. In other words, if a class implements an interface, it must define all the methods declared in that interface. If it doesn’t, the class must be declared as abstract.
It’s important to note that we cannot extend an interface to multiple classes in Java. It is not allowed. To declare an interface, we use the keyword “interface,” and to implement an interface, we use the keyword “implements.”
We tried to elaborate on the concept of Interface in Java in detail with examples. To Read that, you can follow the link.
Interface vs Abstract Class In Java
Let’s analyze the differences between Abstract Classes and Interfaces by considering the following parameters:
Feature | Abstract Class | Interface |
---|---|---|
Keyword | To Create an Abstract Class, you have to use the keyword abstract. | To Create an Interface, you have to use the keyword interface. |
Type Of Variable | The variables may be final, non-final, static and non-static in an abstract class. | In an interface, by default, the variables are static and final. |
Final Variables | The variables may or may not be declared as final. | In Interfaces, variables are, by default, declared as final. |
Access Modifiers | In an abstract class, we can use any access modifiers like public, private, default, and Protected. | In an interface, we can use only public access modifiers. |
Types of Methods | Abstract methods, concrete methods, default, static, private concrete methods (Java 8 onwards) | An interface can have only abstract methods but from Java 8 onwards. interface also supports static and default methods. |
Constructor | An Abstract class can have constructors. | An interface can not have constructors. |
Multiple Inheritance | Abstract class does not support multiple inheritance. As we know, In Java, a class can extend only a single abstract class, but we can implement multiple Java interfaces. | Interface supports multiple inheritance. |
Implementation | You need to use the extends keyword to use an abstract class within your class. | You must use the keyword implements to implement an interface in your class. |
Performance | The performance of the abstract class is faster. | Interfaces are Slower as it requires extra time to search for the actual method in the corresponding class. |
When to Use | An abstract class is useful when multiple classes need to use the same lines of code. Instead of repeating the code in each class, we can create an abstract class and make other classes inherit from it. | An interface is used when we want to achieve multiple inheritance or 100% abstraction. To achieve this, the class needs to implement all the methods declared in the interface. This allows the class to utilize the capabilities provided by the interface fully. |
Execution | An abstract class can have the static main() method to execution. | We can not execute interfaces. |
Syntax | We can declare an Abstract class like the one below: public abstract class demo { public abstract void method1(); public void method2() { System.out.println(“method2”); } } | We can declare an interface like the one below: public interface bank { void load(); void deposit(); } |
Interface or Abstract Class
Deciding whether to use an interface or an abstract class to provide a contract for subclasses depends on various factors and is a design choice. Let’s understand when interfaces are the best option and when we can use abstract classes.
- In Java, each class can only extend one superclass but can implement multiple interfaces. This makes interfaces a good choice for establishing a class hierarchy and contract. It is considered a best practice to code in terms of interfaces in Java.
- If the contract has many methods, an abstract class is more helpful because we can provide a default implementation for some common methods that all subclasses can use. Additionally, if subclasses don’t need to implement a specific method, they can avoid providing its implementation. However, in the case of an interface, the subclass must provide an implementation for all methods, even if it is not needed and is left as an empty block.
- If our base contract frequently changes, using interfaces can create issues because adding new methods to the interface requires modifying all the implementing classes. In contrast, we can provide a default implementation with an abstract class and only update the specific implementing classes that will use the new methods.
Use Abstract Classes and Interface Both
Using interfaces and abstract classes together is considered the best way to design a system. Let’s take an example from the JDK (Java Development Kit): the interface java.util.List contains many methods. To provide a convenient starting point for implementing this interface, there is an abstract class called java.util.AbstractList. This abstract class already includes a basic implementation for all the methods in the List interface. Subclasses can extend this abstract class and only implement the specific methods they need.
The recommended approach is, to begin with an interface as the base, defining the methods that every subclass should implement. Then, if there are additional methods that only certain subclasses require, we can create a new interface by extending the base interface and adding those specific methods. Subclasses can then choose between implementing the base interface or the child interface based on their specific requirements.
As the number of methods grows, it can be helpful to provide a skeletal abstract class that implements the child interface. This abstract class offers flexibility to the subclasses, allowing them to choose between implementing the interface directly or extending the abstract class.
In summary, combining interfaces and abstract classes provide a flexible and modular design approach, allowing for code reuse and accommodating different implementation requirements.
Java 8 Interface Changes
Prior to Java 8, interfaces in Java could only have abstract methods. However, starting from Java 8, interfaces can also have concrete methods, which means methods with a body. By default, all methods in interfaces are public and abstract. However, Java 8 introduced the ability to have default and static methods in interfaces. The purpose of default methods in interfaces is to enable developers to add new methods to interfaces without impacting the classes that implement these interfaces.
Default Methods
In the past, when using Java before version 8, interfaces could only have abstract methods. However, Java 8 brought a new concept called default methods. Default methods are methods in interfaces that can have a body, or instructions on what to do. Default methods are useful because they allow us to add extra functionality to a certain type without causing problems in the classes that implement the interface.
In the old days of Java (Before Java 8), if a new method was added to an interface, it would cause all the classes that implemented that interface.Because we need to provide the implementation of that new method in each and every class.
But sometimes, there are methods that have only one way of being implemented, and it’s not necessary to repeat that implementation in every class. In those cases, we can declare the method as a default method in the interface itself and provide its implementation there.
Default Method Example
For Easy understanding lets take a real world example, Suppose there are several classes are there like HDFC, AXIS, SBI & ICICI. And all the mentioned classes are implements an interface RBI. But in future if RBI added an new method in the RBI interface then we need to update all the classes which implements the RBI interface.
In this example, we have only four classes that use the interface we want to modify. But just imagine if there are hundreds of classes using the same interface! It would be extremely difficult to change the code in all of those classes. That’s why Java 8 introduced something called “default methods.” These methods can be added to an existing interface, and the best part is that we don’t have to implement these methods in all the classes that use the interface. This means we can add default methods to existing interfaces without causing any issues or breaking the code.
package com.softwaretestingo.interfacepackage; interface interfaceWithDefaultMethod { //abstract method void method1(); default void defaultMethod() { System.out.println("Default Method Of Interface"); } } public class DefaultMethodEx1 implements interfaceWithDefaultMethod { @Override public void method1() { System.out.println("Abstract Method Of Interface"); } public static void main(String[] args) { DefaultMethodEx1 obj=new DefaultMethodEx1(); // No Need to Implement the default method obj.defaultMethod(); } }
Output:
Default Method Of Interface
Three Rules To Solve Diamond Problem
In Java, a class can inherit from only one class, but it can implement multiple interfaces. However, when default methods are involved, there can be situations where your class ends up inheriting multiple methods with the same name. To handle such conflicts, Java 8 has defined three rules that you need to follow.
Select classes over interfaces
If your class inherits multiple methods with the same name, the method from the superclass is chosen. (Remember, a class can only inherit from one class.)
package com.softwaretestingo.interfacepackage; interface interfaceWithDefaultMethod1 { default void method1() { System.out.println("Default Method Of Parent Interface"); } } interface childInterface extends interfaceWithDefaultMethod1 { @Override default void method1() { System.out.println("Default Method Of Child Interface"); } } class MyClass implements interfaceWithDefaultMethod1, childInterface { @Override public void method1() { System.out.println("Method From Class"); } } public class DefaultMethodEx2 extends MyClass implements interfaceWithDefaultMethod1,childInterface { public static void main(String[] args) { new DefaultMethodEx2().method1(); } }
Output:
Method From Class
Select most specific interfaces than general interfaces
If your class doesn’t extend any class and inherits multiple methods with the same name from multiple interfaces that belong to the same hierarchy, then the method from the most specific interface is chosen. In other words, if one interface extends another interface, the interface that does the extending is considered more specific than the one it extends.
package com.softwaretestingo.interfacepackage; interface interfaceWithDefaultMethod2 { default void method1() { System.out.println("Default Method Of Parent Interface"); } } interface childInterface2 extends interfaceWithDefaultMethod2 { @Override default void method1() { System.out.println("Default Method Of Child Interface"); } } public class DefaultMethodEx3 implements interfaceWithDefaultMethod2,childInterface2 { public static void main(String[] args) { new DefaultMethodEx3().method1(); } }
Output:
Default Method Of Child Interface
InterfaceName.super.methodName()
If your class doesn’t extend any class and inherits multiple methods with the same name from different interfaces that are not related, you need to override that method in your class. Inside the method’s body, you can explicitly call the desired method from a specific interface using the syntax “InterfaceName.super.methodName()”.
package com.softwaretestingo.interfacepackage; interface interfaceWithDefaultMethod4 { default void method1() { System.out.println("Default Method Of Parent Interface"); } } interface childInterface4 { default void method1() { System.out.println("Default Method Of Child Interface"); } } public class DefaultMethodEx4 implements interfaceWithDefaultMethod4,childInterface4 { @Override public void method1() { interfaceWithDefaultMethod4.super.method1(); } public static void main(String[] args) { new DefaultMethodEx4().method1(); } }
Output:
Default Method Of Parent Interface
Static Methods
Static methods in interfaces are similar to default methods, with one key difference: you can’t override them. But why do we even need static methods in interfaces when we already have default methods?
Well, imagine a situation where you want to provide some implementation in your interface, but you don’t want that implementation to be changed or overridden in the classes that implement the interface. In such cases, you can declare the method as static. By making it static, you ensure that the method’s implementation remains the same across all classes implementing the interface and cannot be modified.
package com.softwaretestingo.interfacepackage; interface interfaceWithStaticMethod { // Abstract Method void method1(); // Default Method default void defaultMethod() { System.out.println("Default Method Of Interface"); } // Static Method static void staticMethod() { System.out.println("Static Method Of Interface"); } } public class StaticMethodEx1 implements interfaceWithStaticMethod { @Override public void method1() { System.out.println("Method1 Class Of Interface"); } public static void main(String[] args) { StaticMethodEx1 obj=new StaticMethodEx1(); obj.method1(); obj.defaultMethod(); } }
Output:
Method1 Class Of Interface Default Method Of Interface
Conclusion:
Abstract classes and interfaces are crucial concepts in Java’s object-oriented programming paradigm. They enable us to achieve abstraction in Java. In this Java article, we explored the distinctions between abstract classes and interfaces based on various factors, including their syntax and implementation.
Furthermore, we discussed the appropriate scenarios for using abstract classes and interfaces in Java. This article serves as a helpful guide to navigating the Java programming landscape.
We appreciate your time in reading our article. If you have any questions regarding abstract classes and interfaces in Java, feel free to leave a comment below.