Tìm hiểu Java Generics qua các ví dụ thực hành về class, method, interface. Nắm vững an toàn kiểu dữ liệu, wildcards và các nguyên tắc lập trình tốt nhất.
Java Generics là một trong những tính năng quan trọng được giới thiệu từ Java 5, giúp lập trình viên viết mã nguồn linh hoạt, tái sử dụng cao và an toàn hơn về kiểu dữ liệu (type safety). Bài viết này sẽ hướng dẫn bạn chi tiết về cách hoạt động, các ví dụ thực hành và nguyên tắc tốt nhất khi làm việc với Generics trong Java.
1. Lợi Ích Của Java Generics
- An toàn kiểu dữ liệu (Type Safety): Phát hiện lỗi sai kiểu dữ liệu ngay ở quá trình biên dịch (compile-time) thay vì chờ đến khi chương trình vận hành (runtime).
- Loại bỏ ép kiểu (Elimination of Casts): Bạn không cần phải ép kiểu thủ công khi lấy phần tử từ danh sách hay đối tượng.
- Tái sử dụng mã nguồn: Cho phép xây dựng các lớp, interface và phương thức hoạt động hiệu quả trên nhiều kiểu dữ liệu khác nhau.
2. Cách Sử Dụng Java Generics
Generics Class
Bạn có thể khai báo một lớp tổng quát bằng cách thêm tham số kiểu trong dấu <>.
public class Box<T> {
private T content;
public void setContent(T content) {
this.content = content;
}
public T getContent() {
return content;
}
}
Cách khởi tạo và sử dụng lớp Generic:
Box<String> stringBox = new Box<>();
stringBox.setContent("Bitech - Kỹ thuật lập trình");
String str = stringBox.getContent(); // Không cần ép kiểu
Generics Method
Phương thức Generic cho phép định nghĩa tham số kiểu riêng biệt, độc lập với lớp chứa nó.
public class GenericMethodExample {
public static <E> void printArray(E[] inputArray) {
for (E element : inputArray) {
System.out.printf("%s ", element);
}
System.out.println();
}
}
3. Wildcards Và Bounds Trong Generics
Wildcard (ký tự ?) đại diện cho kiểu dữ liệu chưa xác định trong Java Generics. Có 3 dạng wildcard chính:
- Unbounded Wildcard (
<?>): Chấp nhận mọi kiểu dữ liệu. Thích hợp khi phương thức chỉ sử dụng các chức năng của lớpObject. - Upper Bounded Wildcard (
<? extends T>): Giới hạn kiểu dữ liệu phải là lớpThoặc lớp con củaT. Thường dùng khi bạn chỉ đọc dữ liệu từ cấu trúc.
public static double sumOfList(List<? extends Number> list) {
double s = 0.0;
for (Number n : list) {
s += n.doubleValue();
}
return s;
}
- Lower Bounded Wildcard (
<? super T>): Giới hạn kiểu dữ liệu phải là lớpThoặc lớp cha củaT. Thường dùng khi bạn cần ghi dữ liệu vào cấu trúc.
4. Các Nguyên Tắc Best Practices Khi Sử Dụng Generics
- Đặt tên tham số kiểu đúng quy ước:
T(Type): Kiểu dữ liệu chung.E(Element): Kiểu phần tử (thường dùng trong Collection).K(Key) vàV(Value): Dùng trong các cấu trúc ánh xạ như Map.
- Tuyệt đối tránh sử dụng Raw Types: Không nên khai báo dạng
List list = new ArrayList();mà hãy luôn chỉ định kiểu nhưList<String>để tránh mất tính an toàn kiểu dữ liệu. - Áp dụng quy tắc PECS (Producer Extends, Consumer Super): Sử dụng
extendsnếu đối tượng của bạn cung cấp/đọc dữ liệu (Producer), và sử dụngsupernếu đối tượng nhận/ghi dữ liệu (Consumer).
Ngày phát hành: 16/06/2026
Nguồn: www.digitalocean.com