Java 8 cho phép định nghĩa method có implementation trong interface thông qua default method và static method. Đây là bước tiến lớn cho backward compatibility và thiết kế API.
Bảng so sánh
| Tiêu chí | Default Method | Static Method |
|---|---|---|
| Từ khóa | default | static |
| Đối tượng gọi | Instance của class implements interface | Interface tên (InterfaceName.method()) |
| Override | Có thể override trong implementing class | Không thể override (chỉ hide – method hiding) |
| Truy cập this | Có (gọi instance method khác) | Không (không có instance context) |
| Kế thừa | Kế thừa cho sub-interface & implementing class | Không kế thừa (chỉ truy cập qua InterfaceName) |
| Mục đích chính | Mở rộng interface mà không break implementing classes. Cung cấp implementation chung. | Utility/helper methods gắn liền với interface (factory, helper). |
| Multiple inheritance conflict | Phải override nếu 2 interface có default method trùng signature | Không conflict (gọi qua InterfaceName rõ ràng) |
Ví dụ minh họa
interface Vehicle {
// Default method: có implementation, có thể override
default void start() {
System.out.println("Vehicle starting... (default)");
checkEngine(); // Gọi private method
}
// Static method: utility, gọi qua Vehicle.checkEngine()
static void checkEngine() {
System.out.println("Engine check: OK");
}
// Private method (Java 9+) – helper cho default/static trong interface
private void log(String msg) {
System.out.println("[LOG] " + msg);
}
// Abstract method – bắt buộc implement
void move();
}
class Car implements Vehicle {
@Override
public void move() {
System.out.println("Car moving on 4 wheels");
}
// Override default method
@Override
public void start() {
Vehicle.checkEngine(); // Gọi static method của interface
System.out.println("Car engine started!");
}
}
class Bike implements Vehicle {
@Override
public void move() {
System.out.println("Bike moving on 2 wheels");
}
// Không override start() → dùng default của Vehicle
}
public class InterfaceMethodsDemo {
public static void main(String[] args) {
Vehicle car = new Car();
Vehicle bike = new Bike();
car.start(); // Car engine started! (overridden)
bike.start(); // Vehicle starting... (default)
// Static method gọi qua Interface
Vehicle.checkEngine(); // Engine check: OK
// Polymorphism
Vehicle[] vehicles = {car, bike};
for (Vehicle v : vehicles) v.move();
}
}
Quy tắc Diamond Problem (Multiple Default Methods)
interface A { default void foo() { System.out.println("A"); } }
interface B { default void foo() { System.out.println("B"); } }
// Class implements cả 2 → BẮT BUỘC override foo()
class C implements A, B {
@Override
public void foo() {
A.super.foo(); // Gọi explicit default của A
// hoặc B.super.foo();
}
}
Best Practices
- Dùng default method để evolve API (thêm method mới vào interface cũ) mà không ép tất cả implementer phải sửa code.
- Dùng static method cho utility methods (factory, validation, helper) liên quan chặt chẽ đến interface.
- Java 9+: Dùng private method trong interface để chia sẻ code giữa default/static methods.
- Tránh lạm dụng default method – interface nên tập trung vào contract (what), không phải implementation (how).