Generic – tham số hoá kiểu dữ liệu, một thuật ngữ được nhắc đến thường xuyên trong quá trình các bạn học ngôn ngữ lập trình Java. Một trong những lợi ích Generic mang lại cho những lập trình viên Java, đó là cho phép người dùng có thể dễ dàng nhận ra các lỗi với các kiểu dữ liệu không hợp lệ.
Để giúp các bạn hiểu rõ hơn về kiến thức lập trình Java nâng cao này, bài chia sẻ dưới đây anh sẽ giải thích các khái niệm, thuật ngữ, các kí tự dùng trong Generic. Đồng thời hướng dẫn cách để tạo ra Generic Class và Generic Method. Cũng như chỉ ra các ưu, nhược điểm của Generic để giúp các bạn hiểu được khi nào thì nên sử dụng trong lập trình Java.
Generic có nghĩa là ta viết các phương thức và lớp để tái sử dụng cho các đối tượng thuộc các kiểu dữ liệu khác nhau (Kiểu dữ liệu như Person , Car , Student, Hotel vv).Nghe có vẻ khó hiểu nên anh sẽ trình bày ví dụ sau đây.
Ví dụ anh muốn viết một chương trình quản lý danh sách học sinh và giáo viên tại trường đào tạo công nghệ thông tin Ada. Anh sẽ sử dụng List để a lưu lại danh sách của học sinh và giáo viên như sau. Nếu các bạn đã quên về List là gì thì có thể tham khảo lại các loại tập hợp trong lập trình java tại (đây)[https://levunguyen.com/laptrinhjava/2020/04/04/cac-tap-hop-trong-lap-trinh-java/]
Oh, có một điều đặc biệt tại sao List lúc thì chứa đối tượng sinh viên , lúc thì chứa đối tượng là giáo viên. Điều này có kỳ lạ không ? Bởi vì List được cài đặt theo cách generic nên ta có thể tái sử dụng lại được các kiểu dữ liệu khác nhau (lúc thì chứa sinh viên , lúc thì chứa giáo viên). Sinh viên và giáo viên là 2 kiểu dữ liệu khác nhau. Do vậy tuỳ vào ngữ cảnh ta truyền vào cho List thì nó có là danh sách sinh viên (List <Student >) hay nó có thể là danh sách giáo viên (List < Teacher >). Nói cách khác Generic thì ta định nghĩa một kiểu dữ liệu chung chung , và tuỳ vào ngữ cảnh ta truyền vào (Student hay Teacher) thì ta sẽ có tập hợp tương ứng.
Ví dụ ta tạo Generic Class tên là Box. Mọi người chú ý để tạo 1 class là generic ta thêm < T > vào sau class. <T> là ký hiệu của Generic , ta sẽ tìm hiểu ở phần tiếp theo.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
Box<String> stringBox = new Box<String>();
integerBox.add(new Integer(10));
stringBox.add(new String("Hello World"));
System.out.printf("Integer Value :%d\n\n", integerBox.get());
System.out.printf("String Value :%s\n", stringBox.get());
}
}
Kết quả nhận được sẽ là.
Integer Value :10
String Value :Hello World
Như vậy ví dụ trên ta tạo một class Box là generic có 2 phương thức là add và get .Khi ta sử dụng Generic Box trong hàm main ( 58,59) . Tuỳ vào ngữ cảnh mà Generic Box có thể chứa kiểu đối tượng Integer (Box
Ví dụ ta viết một phương thức in tất cả các phần tử là Generic. Mọi người chú ý tham số truyền vào trong phương thức là chữ <E> đó là tham khi ta muốn viết một hàm generic. Tuỳ vào tham số truyền vào là kiểu dữ liệu gì . Ta cũng in được các phần tử con trong tập hợp đó Ví dụ ta viết phương thức printArrayGeneric sau truyền vào tham số là một kiểu generic. Ký tự <E> ta sẽ bàn trong phần tiếp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class GenericMethodTest {
// generic method printArrayGeneric
public static < E > void printArrayGeneric( E[] inputArrayGeneric ) {
// Display array elements
for(E elementGeneric : ArrayGeneric) {
System.out.printf("%s ", elementGeneric);
}
System.out.println();
}
public static void main(String args[]) {
// Create arrays of Integer, Double and Character
Integer[] intArrayGeneric = { 2,4,6,8,10 };
Double[] doubleArrayGeneric = { 2.1, 3.2, 4.3, 5.4 };
Character[] charArrayGeneric = { 'L', 'E', 'V', 'U', 'O' };
System.out.println("Array intArrayGeneric contains:");
printArrayGeneric(intArrayGeneric); // pass an Integer array
System.out.println("\nArray doubleArray contains:");
printArrayGeneric(doubleArrayGeneric); // pass a Double array
System.out.println("\nArray characterArray contains:");
printArrayGeneric(charArrayGeneric); // pass a Character array
}
}
Kết quả nhận được sẽ là.
Array intArrayGeneric contains: 2 4 6 8 10
Array doubleArrayGeneric contains: 2.1 3.2 4.3 5.4
Array characterArray contains: L E V U O
Như vậy ở ví dụ trên ta tạo ra một phương thức in ra màn hình là generic . Tuỳ thuộc vào đối số truyền vào là Integer , String, hay Double thì phương thức in đều in ra được các phần tử Nếu ta truyền đối số là Integer thì sẽ nhận được kết quả là các số nguyên trong tập hợp được in ra . Nếu ta truyền đối số là Double thì ta sẽ nhận được các số thực được in ra . Như vậy ta chỉ viết code 1 lần và sử dụng được cho tất cả các đối số là những kiểu dữ liệu khác nhau.
Như ta thấy ở các ví dụ trên ta dùng các ký tự đặt biệt như <T> hay <E> để đặt tên các kiểu dữ liệu và tham số. Ta có thể dùng các từ khác cũng được như X,Y,Z . Nhưng do <T> hay <E> là các qui ước chung cho các lập trình viên đọc cho dể hiểu, dể bảo trì nên ta không nên đặt các từ khác gây nhầm lẫn. Chúng ta có các qui ước sau.
Trong Generic nhiều lúc chúng ta sẽ gặp các ký tự đại diên như : (?),(wildcard), nó đại diện cho một loại dữ liệu không rõ ràng.
Ký tự đại diện <?> chấp nhận tất cả các loại đối số (chứa mọi kiểu đối tượng). Ví dụ: Collection<?> mô tả một tập hợp chấp nhận tất cả các loại đối số kiểu String, Integer, Boolean, …
Ký tự đại diện <? extends type>: Các đối tượng bất kỳ nào cũng được nhưng bắt buộc phải có cùng kiểu dữ liệu mới hợp lệ . Ví dụ: List<? extends Number> mô tả một danh sách, nơi mà các phần tử là kiểu Number hoặc kiểu con của Number.
Ký tự đại diện <? super type> chấp nhận bất ký đối tượng nào miễn là đối tượng này là cha của type hoặc đối tượng của type.
Trong lập trình chúng ta thường sử dụng nhiều generic trong Abstract và Interface để code trở nên gọn hơn tái sử dụng được nhiều lần.
1
2
3
4
abstract class Animal<T> {
protected abstract <T> getAnimalName();
}
1
2
3
4
5
6
7
public interface GenericDao<T> {
void insert(T obj);
void update(T obj);
}
Và bây giờ, hãy cùng xem code demo ở bên dưới để hiểu rõ hơn nhé .