Java 8 introduced default methods in interfaces, allowing interfaces to contain method implementations in addition to abstract method declarations. This enhancement increased the flexibility of interfaces and reduced the need to use abstract classes solely for sharing common behavior. However, interfaces and abstract classes still serve different design purposes.
Key Points: • Interfaces are preferred for defining contracts and enabling multiple inheritance of behavior through default methods. • Abstract classes are suitable when related classes need to share state, constructors, or protected members. • Default methods help extend existing interfaces without breaking existing implementations, improving backward compatibility.
Example: Suppose multiple payment providers such as CreditCardPayment, UpiPayment, and WalletPayment need a common validation method. A default method in an interface can provide shared validation logic while allowing each implementation to define its own payment processing behavior.
Code Example:
interface PaymentService {
void processPayment();
default void validatePayment() {
System.out.println("Validating Payment");
}
}
class CreditCardPayment implements PaymentService {
@Override
public void processPayment() {
System.out.println("Processing Credit Card Payment");
}
}
public class Main {
public static void main(String[] args) {
PaymentService payment =
new CreditCardPayment();
payment.validatePayment();
payment.processPayment();
}
}Interview Tip: A concise interview answer is: After Java 8, interfaces became more powerful through default methods, making them a preferred choice for defining contracts and sharing common behavior across unrelated classes. However, abstract classes are still better when shared state, constructors, or partial implementations are required. The choice depends on whether you need behavior sharing only (interface) or behavior plus state management (abstract class).