Generics trong Java

Định nghĩa

Generic programming trong Java là việc ta cho phép 1 phương thức hay 1 class xử lý các đối tượng thuộc 1 kiểu dữ liệu tuỳ ý (generic). Kiểu dữ liệu tuỳ ý này có dạng  compile-time type safety. Tức là 1 khi nó đã được khai báo, trình biên dịch sẽ không chấp nhận việc phương thức hay class chứa xử lý các kiểu dữ liệu khác.

Để dễ hiểu hơn mình sẽ lấy 1 ví dụ đơn giản thế này. Ta khai báo 1 ArrayList như sau:

Bạn thấy listName là 1 ArrayList và nó chỉ chấp nhận các giá trị String. Ở đây ArrayListclass chứa và String chính là kiểu dữ liệu “tuỳ ý” mà mình nói ở trên.

Mình lại lấý 1 ví dụ khác:

Lần này thì ArrayList lại chỉ chấp nhận xử lý kiểu dữ liệu Integer, bởi vì Integer đã được khai báo với ArrayList.

Tạo 1 generic class (lớp chứa)

Giống như mọi class khác, generic class được khai báo với từ khoá class. Điểm khác biệt ở đây là nó còn có thêm cặp <T> để tượng trưng cho kiểu dữ liệu mà nó sẽ xử lý. Ví dụ:

Như các bạn thấy <T> tượng trưng cho kiểu dữ liệu sẽ được xử lý bởi Param. Nó có thể là bất cứ kiểu gì: Integer, String, Boolean, Animal, Human, ….. Nhưng 1 khi đã được khai báo, lớp chứa của nó (generic class) sẽ chỉ chấp nhận xử lý kiểu dữ liệu đã được khai báo.

Giờ mình sẽ tạo ra 1 đối tượng Param chuyên xử lý kiểu dữ liệu Integer:

Mình sẽ tạo 1 đối tượng Param khác chuyên xử lý kiểu String:

Tương tự, bạn có thể khai báo bất cứ kiểu dữ liệu nào để generic class Param xử lý.

Kế thừa generic class

Việc kế thừa generic class thực chất chẳng khác gì kế thừa 1 class bình thường

Ví dụ mình khai báo 1 generic class AbstractParam như sau (lớp này sẽ được kế thừa bởi các lớp khác):

Không khác gì 1 lớp bình thường ngoài việc khai báo thêm kiểu dữ liệu generic <T> phải không?

Giờ ta sẽ tạo 1 lớp Email kế thừa AbstractParam:

Ta đã tạo 1 lớp Email kế thừa AbstracParam<String>, điều này có nghĩa là:

  • Ta đã chỉ định generic type là String
  • Thuộc tính value trong lớp Email sẽ có kiểu là String.

Ta sẽ test 2 điều trên bằng câu lệnh sau:

Giờ mính sẽ khai báo 1 lớp khác là Age:

Tương tự như class Email, nhưng lần này Age được khai báo là generic class của kiểu Int, có nghĩa là trường value của Age chỉ có thể mang kiểu Int:

Mình sẽ lấy thêm 1 ví dụ nữa, ta khai báo class Height như sau:

Ở đây khi định nghĩa Height, ta chưa khai báo rõ kiểu generic (trong 2 trường hợp trước ta đã chỉ ra luôn StringInteger), tức là Height có thể xử lý bất kỳ kiểu dữ liệu gì mà không bị “ép buộc” phải xử lý StringInteger như class EmailAge. Ví dụ:

Đó là những kiến thức cơ bản về kế thừa generic class, hy vọng mình diễn đạt dễ hiểu.

Khai báo nhiều dữ liệu generic (Multiple type parameters)

Ta không những có thể khai báo kiểu dữ liệu generic cho class xử lý, ta còn có thể khai báo tuỳ thích số lượng các kiểu generic. Ví dụ:

Lớp trên sẽ được sử dụng kiểu thế này:

T , ? super T và ? extends T

Đôi khi ta không nhất thiết phải khai báo generic Type 1 cách chính xác, ? super T? extends T giúp ta điều này. Cụ thể:

  • ? super T tượng trưng cho các lớp là lớp cha của T
  • ? extends T tượng trưng cho các lớp kế thừa T

Để rõ hơn mình sẽ lấy ví dụ như sau. Mình tạo các class:

Giờ ta sẽ sử dụng các câu lệnh sau để thấy rõ được cách sử dụng của T, ? super T? extends T

 

 

Hãy chia sẻ

One comment

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *