Java - Generics

Xin chào, những pháp sư Java tương lai! Hôm nay, chúng ta sẽ bắt đầu một chuyến hành trình thú vị vào thế giới của Java Generics. Đừng lo lắng nếu bạn là người mới bắt đầu lập trình; tôi sẽ là người bạn thân thiện dẫn đường cho bạn trong cuộc phiêu lưu này. Vậy, hãy lấy keyboards của bạn và cùng nhau nhảy vào!

Java - Generics

什么是Generics?

Hãy tưởng tượng bạn đang ở một cửa hàng kem, và bạn có một容器 có thể chứa bất kỳ hương vị kem nào. Đó chính là những gì Generics trong Java - chúng cho phép bạn tạo ra các lớp, giao diện và phương thức có thể làm việc với các loại dữ liệu khác nhau, giống như容器 kem ma thuật của chúng ta!

Tại sao lại sử dụng Generics trong Java?

Bạn có thể tự hỏi, "Tại sao chúng ta cần container ma thuật này?" Well, những người bạn trẻ, Generics mang lại nhiều lợi ích:

  1. Bảo mật loại: Chúng giúp ngăn ngừa lỗi bằng cách đảm bảo bạn đang sử dụng các loại đúng.
  2. Tái sử dụng mã: Bạn có thể viết mã hoạt động với nhiều loại dữ liệu khác nhau.
  3. Loại bỏ việc ép kiểu: Không cần ép kiểu tẻ nhạt nữa!

Hãy xem một ví dụ đơn giản:

public class MagicalContainer<T> {
private T item;

public void setItem(T item) {
this.item = item;
}

public T getItem() {
return item;
}
}

Trong ví dụ này, T là một tham số loại. Nó giống như nói, "Container này có thể chứa bất kỳ loại vật phẩm nào." Chúng ta có thể sử dụng nó như sau:

MagicalContainer<String> stringContainer = new MagicalContainer<>();
stringContainer.setItem("Hello, Generics!");
String message = stringContainer.getItem();

MagicalContainer<Integer> intContainer = new MagicalContainer<>();
intContainer.setItem(42);
int number = intContainer.getItem();

Thấy chưa, chúng ta có thể sử dụng cùng một lớp MagicalContainer cho các loại khác nhau? Đó là sức mạnh của Generics!

Các loại Generics trong Java

Bây giờ chúng ta đã thử nghiệm với Generics, hãy cùng khám phá các loại Generics khác nhau trong Java. Đó giống như học các spells khác nhau trong pháp thuật lập trình của chúng ta!

1. Lớp Generic

Chúng ta đã thấy một ví dụ về lớp generic với MagicalContainer. Dưới đây là một ví dụ khác:

public class Pair<K, V> {
private K key;
private V value;

public Pair(K key, V value) {
this.key = key;
this.value = value;
}

public K getKey() { return key; }
public V getValue() { return value; }
}

Lớp Pair này có thể chứa hai vật phẩm có thể khác loại. Chúng ta có thể sử dụng nó như sau:

Pair<String, Integer> pair = new Pair<>("Age", 25);
System.out.println(pair.getKey() + ": " + pair.getValue());  // Xuất: Age: 25

2. Phương thức Generic

Chúng ta cũng có thể có phương thức generic trong các lớp không generic. Đó giống như có một spell ma thuật hoạt động với bất kỳ nguyên liệu nào!

public class MagicTricks {
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.print(element + " ");
}
System.out.println();
}
}

Chúng ta có thể sử dụng phương thức này với các mảng loại khác nhau:

Integer[] intArray = {1, 2, 3, 4, 5};
Double[] doubleArray = {1.1, 2.2, 3.3, 4.4, 5.5};
String[] stringArray = {"Hello", "Generics", "World"};

MagicTricks.printArray(intArray);
MagicTricks.printArray(doubleArray);
MagicTricks.printArray(stringArray);

3. Tham số loại có giới hạn

Đôi khi, chúng ta muốn giới hạn các generic của mình trong một số loại. Đó giống như nói, "Spell này chỉ hoạt động trên các sinh vật ma thuật!"

public class NumberContainer<T extends Number> {
private T number;

public NumberContainer(T number) {
this.number = number;
}

public double getSquareRoot() {
return Math.sqrt(number.doubleValue());
}
}

Trong ví dụ này, T phải là một subclass của Number. Chúng ta có thể sử dụng nó với Integer, Double, v.v., nhưng không thể sử dụng với String.

NumberContainer<Integer> intContainer = new NumberContainer<>(16);
System.out.println(intContainer.getSquareRoot());  // Xuất: 4.0

NumberContainer<Double> doubleContainer = new NumberContainer<>(25.0);
System.out.println(doubleContainer.getSquareRoot());  // Xuất: 5.0

// Điều này sẽ gây ra lỗi thời gian biên dịch:
// NumberContainer<String> stringContainer = new NumberContainer<>("Not a number");

Lợi ích của Generics trong Java

Bây giờ chúng ta đã khám phá các loại Generics khác nhau, hãy tóm tắt lợi ích của chúng:

Lợi ích Mô tả
Bảo mật loại Lấy lỗi type tại thời gian biên dịch thay vì thời gian chạy
Tái sử dụng mã Viết một lần, sử dụng với nhiều loại
Loại bỏ việc ép kiểu Không cần ép kiểu rõ ràng, giảm thiểu lỗi tiềm ẩn
Hiệu suất tốt hơn Tránh kiểm tra và ép kiểu thời gian chạy
Cho phép các thuật toán generic Viết các thuật toán hoạt động trên các bộ sưu tập loại khác nhau

Kết luận

Chúc mừng, những pháp sư Java trẻ! Bạn vừa học về thế giới ma thuật của Java Generics. Nhớ rằng, giống như bất kỳ spell mạnh mẽ nào, Generics cần phải luyện tập để thành thạo. Đừng nản lòng nếu cảm thấy khó khăn ban đầu - ngay cả những pháp sư vĩ đại nhất cũng bắt đầu từ đâu đó!

Trong khi tiếp tục hành trình lập trình Java của bạn, bạn sẽ thấy Generics xuất hiện ở khắp mọi nơi, đặc biệt là khi làm việc với các bộ sưu tập và API. Chúng là một công cụ thiết yếu để viết mã sạch, tái sử dụng và bảo mật loại.

Tiếp tục luyện tập, 保持好奇心, và trước khi bạn biết điều đó, bạn sẽ casting các spell Generics như một true Java sorcerer! Đến gặp lại, chúc mã của bạn không có lỗi và các lần biên dịch nhanh chóng!

Credits: Image by storyset