1. Interface là gì?
Nếu abstract class là bản vẽ của một ngôi nhà, thì interface giống như một thỏa thuận hay “hợp đồng” để thực hiện những công việc nhất định. Ví dụ, khi bạn gọi thợ sửa ống nước, bạn kỳ vọng họ có thể “sửa vòi nước” và “khắc phục rò rỉ”. Họ làm như thế nào — bạn không quan tâm; điều quan trọng là có kết quả. Trong Java, interface chính là hợp đồng như vậy: nó nêu những phương thức cần được triển khai, nhưng không nói làm như thế nào.
Ngắn gọn và trọng tâm:
Interface là một kiểu đặc biệt trong Java, định nghĩa tập các phương thức mà các lớp ký vào interface đó bắt buộc phải triển khai.
- Interface chỉ mô tả “làm gì”, chứ không “làm như thế nào”.
- Trước Java 8, interface không chứa phần triển khai phương thức.
- Interface là một hợp đồng thuần túy: nếu một lớp triển khai interface, lớp đó phải triển khai tất cả các phương thức của nó.
Vì sao điều này tiện lợi?
- Có thể “gắn” cho một lớp nhiều interface — tức là cho nó nhiều “vai trò”.
- Cho phép xây dựng kiến trúc linh hoạt, có khả năng mở rộng, nơi các lớp có thể triển khai các khả năng khác nhau.
- Interface được dùng rộng rãi trong thư viện chuẩn Java (ví dụ: Comparable, Serializable, Runnable, v.v.).
2. Cú pháp khai báo interface
Khai báo interface trong Java — đơn giản vô cùng. Ta dùng từ khóa interface. Trước Java 8, các phương thức của interface mặc định được coi là public abstract, ngay cả khi không ghi rõ. Điều đó có nghĩa là: phương thức phải được triển khai trong lớp triển khai interface.
Ví dụ về interface
public interface Movable {
void move(int x, int y);
}
- Ở đây ta khai báo interface Movable (có thể hiểu là “có thể di chuyển”).
- Bên trong có phương thức move(int x, int y). Không có phần thân — chỉ có chữ ký. Đây chính là “hợp đồng”: “nếu bạn triển khai Movable — hãy triển khai move”.
Đặc điểm cú pháp
- Các phương thức trong interface không có thân (trước Java 8).
- Tất cả phương thức của interface mặc định là public abstract (có thể không cần viết rõ).
- Interface chỉ có thể chứa hằng số (public static final), không có trường thông thường.
Ví dụ với hằng số
public interface Constants {
int MAX_SPEED = 100; // public static final theo mặc định
}
3. Khác biệt giữa interface và class
Interface không phải là class! Hãy xem khác nhau ở điểm nào.
| Lớp (kể cả abstract) | Interface |
|---|---|
| Có thể chứa các trường (trạng thái) | Không thể chứa trường (chỉ có hằng số) |
| Có thể chứa phần triển khai phương thức | Trước Java 8, interface không có phần triển khai, chỉ có chữ ký |
| Có thể được tạo qua new (nếu không phải abstract) | Không thể tạo trực tiếp |
| Kế thừa chỉ đơn ( extends ) | Một lớp có thể triển khai nhiều interface ( implements ) |
| Dùng để mô tả “nó là gì” | Dùng để mô tả “nó có thể làm gì” |
Class triển khai interface bằng implements
public class Robot implements Movable {
@Override
public void move(int x, int y) {
System.out.println("Robot di chuyển tới điểm (" + x + ", " + y + ")");
}
}
- Lớp Robot triển khai interface Movable.
- Từ khóa implements — “triển khai”.
- Bắt buộc triển khai tất cả các phương thức của interface (nếu không sẽ lỗi biên dịch).
- Đừng quên annotation @Override — không bắt buộc, nhưng giúp trình biên dịch và bạn tránh sai sót.
4. Ví dụ sử dụng interface
Hãy viết một ví dụ đơn giản để thấy nó hoạt động trong thực tế. Giả sử ta có interface Movable, và ta muốn các lớp khác nhau có thể “di chuyển”: robot, ô tô, động vật...
Bước 1. Khai báo interface
public interface Movable {
void move(int x, int y);
}
Bước 2. Triển khai interface trong class
public class Robot implements Movable {
@Override
public void move(int x, int y) {
System.out.println("Robot di chuyển tới điểm (" + x + ", " + y + ")");
}
}
Bước 3. Sử dụng interface
public class Main {
public static void main(String[] args) {
Movable m = new Robot(); // Biến có kiểu là interface!
m.move(10, 20); // Kết quả in ra: Robot di chuyển tới điểm (10, 20)
}
}
Lưu ý
- Ta có thể khai báo một biến kiểu interface (Movable m) và gán cho nó một đối tượng của lớp triển khai interface đó (new Robot()).
- Điều này cho phép viết mã tổng quát làm việc với bất kỳ đối tượng “có thể di chuyển” nào, mà không cần biết đó thực sự là lớp nào.
Lỗi biên dịch nếu không triển khai phương thức
Error: Class 'Robot' must either be declared abstract or implement abstract method 'move(int, int)' in 'Movable'
Đó là sức mạnh của interface — nó đảm bảo rằng mọi lớp triển khai đều có các phương thức cần thiết.
5. Interface trong thư viện chuẩn Java
Interface không chỉ là chủ đề “vỡ lòng”. Chúng được dùng khắp nơi trong thư viện chuẩn Java. Một vài ví dụ:
- Comparable<T> — interface để so sánh đối tượng (ví dụ khi sắp xếp).
- Runnable — interface để chạy luồng.
- Serializable — interface đánh dấu (marker), chỉ ra rằng đối tượng có thể được tuần tự hóa.
- List, Set, Map — các interface của bộ sưu tập (collection).
Ví dụ: Comparable
public class Person implements Comparable<Person> {
String name;
int age;
// Constructor và các phương thức khác...
@Override
public int compareTo(Person other) {
return this.age - other.age;
}
}
Bây giờ các đối tượng Person có thể được sắp xếp vì chúng triển khai interface Comparable.
6. Sơ đồ trực quan: interface hoạt động như thế nào
+-------------------+ +-------------------+
| interface | | class |
| Movable |<--------| Robot |
|-------------------| |-------------------|
| +move(int, int) | | +move(int, int) |
+-------------------+ +-------------------+
- Mũi tên cho thấy class Robot triển khai interface Movable.
- Interface chỉ xác định “cần có gì”, còn class — “hoạt động như thế nào”.
Liên hệ thực tế
Interface trong Java giống như giấy phép lái xe. Nếu bạn có bằng lái (bạn triển khai interface “Người lái xe”), nghĩa là bạn biết lái ô tô. Cách bạn thực hiện cụ thể ra sao — là chi tiết: có người lái cẩn thận, có người lái nhanh, nhưng quan trọng là bạn đã cam kết rằng mình biết làm việc đó.
7. Ví dụ thực tế: tiếp tục ứng dụng của chúng ta
public interface Movable {
void move(int x, int y);
}
public class Animal implements Movable {
protected String name;
public Animal(String name) {
this.name = name;
}
@Override
public void move(int x, int y) {
System.out.println(name + " di chuyển tới điểm (" + x + ", " + y + ")");
}
}
public class Robot implements Movable {
private String model;
public Robot(String model) {
this.model = model;
}
@Override
public void move(int x, int y) {
System.out.println("Robot " + model + " đi tới tọa độ (" + x + ", " + y + ")");
}
}
public class Main {
public static void main(String[] args) {
Movable[] movables = {
new Animal("Barsik"),
new Robot("R2D2")
};
for (Movable m : movables) {
m.move(5, 10);
}
}
}
Kết quả:
Barsik di chuyển tới điểm (5, 10)
Robot R2D2 đi tới tọa độ (5, 10)
Chúng ta đã tạo một mảng các đối tượng kiểu Movable. Bên trong có thể là bất kỳ đối tượng nào triển khai interface này! Mã trong vòng lặp không biết chính xác đó là gì — động vật hay robot — nhưng biết rằng mỗi đối tượng đều có thể gọi move.
8. Các lỗi thường gặp khi làm việc với interface
Lỗi № 1: cố gắng tạo đối tượng interface trực tiếp. Interface là hợp đồng, không phải đối tượng cụ thể. Không thể viết new Movable() — sẽ gây lỗi biên dịch. Cần tạo đối tượng của các lớp triển khai interface.
Lỗi № 2: không triển khai tất cả phương thức của interface. Nếu một lớp triển khai interface nhưng không triển khai tất cả các phương thức, trình biên dịch sẽ báo lỗi: “Class must either be declared abstract or implement abstract method ...”. Nếu bạn không muốn triển khai hết — hãy khai báo lớp là abstract.
Lỗi № 3: quên bộ sửa đổi truy cập. Các phương thức của interface luôn là public (ngay cả khi không viết rõ). Trong lớp triển khai không được hạ mức độ truy cập, vì vậy phương thức cũng phải là public.
Lỗi № 4: cố gắng thêm trường thông thường vào interface. Trong interface chỉ có thể khai báo hằng số (public static final). Không thể thêm các trường (không tĩnh) thông thường.
GO TO FULL VERSION