Java - Generics

Sẽ thật tuyệt nếu chúng ta có thể viết một phương thức sắp xếp duy nhất có thể sắp xếp các phần tử trong mảng Số nguyên, mảng Chuỗi hoặc một mảng thuộc bất kỳ kiểu nào hỗ trợ sắp xếp.

Java Generic các phương thức và các lớp chung cho phép người lập trình xác định, với một khai báo phương thức duy nhất, một tập các phương thức liên quan hoặc với một khai báo lớp đơn, một tập các kiểu liên quan, tương ứng.

Generics cũng cung cấp sự an toàn cho kiểu thời gian biên dịch cho phép người lập trình bắt các kiểu không hợp lệ tại thời điểm biên dịch.

Sử dụng khái niệm Java Generic, chúng ta có thể viết một phương thức chung để sắp xếp một mảng đối tượng, sau đó gọi phương thức chung với mảng Số nguyên, Mảng đôi, Mảng chuỗi, v.v. để sắp xếp các phần tử của mảng.

Phương pháp chung

Bạn có thể viết một khai báo phương thức chung duy nhất có thể được gọi với các đối số thuộc các kiểu khác nhau. Dựa trên các loại đối số được truyền cho phương thức chung, trình biên dịch xử lý từng lệnh gọi phương thức một cách thích hợp. Sau đây là các quy tắc để xác định các Phương thức Chung -

  • Tất cả các khai báo phương thức chung đều có phần tham số kiểu được phân cách bằng dấu ngoặc nhọn (<và>) đứng trước kiểu trả về của phương thức (<E> trong ví dụ tiếp theo).

  • Mỗi phần tham số kiểu chứa một hoặc nhiều tham số kiểu được phân tách bằng dấu phẩy. Tham số kiểu, còn được gọi là biến kiểu, là một số nhận dạng chỉ định tên kiểu chung.

  • Các tham số kiểu có thể được sử dụng để khai báo kiểu trả về và hoạt động như trình giữ chỗ cho các kiểu đối số được truyền cho phương thức chung, được gọi là đối số kiểu thực.

  • Phần thân của một phương thức chung được khai báo giống như của bất kỳ phương thức nào khác. Lưu ý rằng các tham số kiểu chỉ có thể đại diện cho các kiểu tham chiếu, không phải kiểu nguyên thủy (như int, double và char).

Thí dụ

Ví dụ sau minh họa cách chúng ta có thể in một mảng có kiểu khác nhau bằng một phương thức Chung duy nhất:

public class GenericMethodTest {
   // generic method printArray
   public static < E > void printArray( E[] inputArray ) {
      // Display array elements
      for(E element : inputArray) {
         System.out.printf("%s ", element);
      }
      System.out.println();
   }

   public static void main(String args[]) {
      // Create arrays of Integer, Double and Character
      Integer[] intArray = { 1, 2, 3, 4, 5 };
      Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
      Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };

      System.out.println("Array integerArray contains:");
      printArray(intArray);   // pass an Integer array

      System.out.println("\nArray doubleArray contains:");
      printArray(doubleArray);   // pass a Double array

      System.out.println("\nArray characterArray contains:");
      printArray(charArray);   // pass a Character array
   }
}

Điều này sẽ tạo ra kết quả sau:

Đầu ra

Array integerArray contains:
1 2 3 4 5 

Array doubleArray contains:
1.1 2.2 3.3 4.4 

Array characterArray contains:
H E L L O

Các thông số kiểu giới hạn

Có thể có những lúc bạn muốn hạn chế các loại kiểu được phép chuyển cho tham số kiểu. Ví dụ, một phương thức hoạt động trên các số có thể chỉ muốn chấp nhận các thể hiện của Số hoặc các lớp con của nó. Đây là những gì các tham số kiểu bị giới hạn dành cho.

Để khai báo một tham số kiểu có giới hạn, hãy liệt kê tên của tham số kiểu, theo sau là từ khóa expand, tiếp theo là giới hạn trên của nó.

Thí dụ

Ví dụ sau minh họa cách dùng để mở rộng theo nghĩa chung là "mở rộng" (như trong các lớp) hoặc "thực hiện" (như trong các giao diện). Ví dụ này là phương thức Chung để trả về giá trị lớn nhất trong ba đối tượng có thể so sánh được -

public class MaximumTest {
   // determines the largest of three Comparable objects
   
   public static <T extends Comparable<T>> T maximum(T x, T y, T z) {
      T max = x;   // assume x is initially the largest
      
      if(y.compareTo(max) > 0) {
         max = y;   // y is the largest so far
      }
      
      if(z.compareTo(max) > 0) {
         max = z;   // z is the largest now                 
      }
      return max;   // returns the largest object   
   }
   
   public static void main(String args[]) {
      System.out.printf("Max of %d, %d and %d is %d\n\n", 
         3, 4, 5, maximum( 3, 4, 5 ));

      System.out.printf("Max of %.1f,%.1f and %.1f is %.1f\n\n",
         6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ));

      System.out.printf("Max of %s, %s and %s is %s\n","pear",
         "apple", "orange", maximum("pear", "apple", "orange"));
   }
}

Điều này sẽ tạo ra kết quả sau:

Đầu ra

Max of 3, 4 and 5 is 5

Max of 6.6,8.8 and 7.7 is 8.8

Max of pear, apple and orange is pear

Các lớp chung

Một khai báo lớp chung trông giống như một khai báo lớp không chung chung, ngoại trừ việc tên lớp được theo sau bởi một phần tham số kiểu.

Như với các phương thức chung, phần tham số kiểu của một lớp chung có thể có một hoặc nhiều tham số kiểu được phân tách bằng dấu phẩy. Các lớp này được gọi là lớp được tham số hóa hoặc kiểu được tham số hóa vì chúng chấp nhận một hoặc nhiều tham số.

Thí dụ

Ví dụ sau minh họa cách chúng ta có thể định nghĩa một lớp chung:

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());
   }
}

Điều này sẽ tạo ra kết quả sau:

Đầu ra

Integer Value :10
String Value :Hello World