Java: Phương thức generic


Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên

Java cũng hỗ trợ phương thức generic. Phương thức generic được định nghĩa cho một phương thức cụ thể và có cùng chức năng như tham số kiểu có cho các lớp generic. Các phương thức generic có thể xuất hiện trong các lớp generic cũng như trong các lớp non-generic. Phương thức generic có thể được định nghĩa là một phương thức với các tham số kiểu. Các phương thức generic phù hợp nhất cho các phương thức được nạp chồng thực hiện các hoạt động giống hệt nhau cho các loại đối số khác nhau. Việc sử dụng các phương thức generic làm cho các phương thức nạp chồng trở nên nhỏ gọn hơn và dễ lập trình hơn.

Một phương thức generic cho phép các tham số kiểu được sử dụng để tạo sự phụ thuộc giữa kiểu đối số của một phương thức và kiểu trả về của nó. Kiểu trả về không phụ thuộc vào tham số kiểu hoặc bất kỳ đối số nào khác của phương thức. Điều này cho thấy rằng đối số kiểu đang được sử dụng để đa hình.

Phạm vi của tham số kiểu của phương thức là khai báo phương thức. Phạm vi của tham số kiểu cũng có thể là tham số kiểu của các tham số kiểu khác.

Cú pháp:

public <T> void display(T[] val)

Ví dụ sau hiển thị việc sử dụng một phương thức generic.

class NumberList<T> {
  public <T> void display(T[] val) {
    for (T element : val) {
      System.out.printf("Values are: %s " ,element);
    }
  }

  public static void main(String[] args) {
    Integer[] intValue = {1, 7, 9, 15};
    NumberList<Integer> listObj = new NumberList<>();
    listObj.display(intValue);
  }
}

Ví dụ trên sử dụng một phương thức generic là display(), chấp nhận một tham số mảng làm đối số của nó. Hình dưới hiển thị đầu ra.

Phương thức generic

Một lớp generic có thể có hai hoặc nhiều tham số kiểu.

Ví dụ sau trình bày cách khai báo một lớp có hai tham số kiểu.

import java.util.*;
public class TestQueue<DataType1, DataType2> {
  private final DataType2 num;
  private LinkedList<DataType1> items = new LinkedList<>();

  public TestQueue(DataType2 num) {
    this.num = num;
  }
  public void enqueue(DataType1 item) {
    items.addLast(item);
  }
  public DataType1 dequeue() {
    return items.removeLast();
  }
}

Giống như bất kỳ lớp nào khác, các lớp generic cũng có thể được phân lớp bởi các lớp generic hoặc non-generic. Một lớp con non-generic có thể mở rộng một lớp cha bằng cách chỉ định các tham số cần thiết và do đó làm cho nó trở nên cụ thể.

Ví dụ sau trình bày cách khai báo một lớp con non-generic.

public class MyTest extends TestQueue<String,Integer> {
  public MyTest(Integer num) {
    super(num);
  }
  public static void main(String[] args) {
    MyTest test = new MyTest(new Integer(10));
    test.enqueue("Hello");
    test.enqueue("Java");
    System.out.println((String) test.dequeue());
  }
}

Trong ví dụ trên, một lớp con non-generic được tạo tên là MyTest với một phần khởi tạo generic cụ thể là MyTest extends TestQueue<String, Integer> .

Hình dưới đây thể hiện kết quả.

Generic1

Ví dụ sau trình bày việc tạo một lớp con generic.

class MyTestQueue<DataType> extends TestQueue<DataType> {
  public static void main(String[] args) {
    MyTestQueue<String> test = new MyTestQueue<String>();
    test.enqueue("Hello");
    test.enqueue("Java");
    System.out.println((String) test.dequeue());
  }
}

Khai báo các phương thức generic

Để tạo các phương thức và hàm tạo generic, các tham số kiểu được khai báo trong phương thức và signature của hàm tạo. Tham số kiểu được chỉ định trước kiểu trả về của phương thức và trong dấu ngoặc nhọn. Các tham số kiểu có thể được sử dụng làm kiểu đối số, kiểu trả về và kiểu biến cục bộ trong khai báo phương thức generic. Có thể có nhiều hơn một loại tham số kiểu, mỗi loại được phân tách bằng dấu phẩy. Các tham số kiểu này hoạt động như trình giữ chỗ cho các kiểu dữ liệu của đối số kiểu thực tế, được truyền cho phương thức. Các kiểu dữ liệu nguyên thủy không thể được biểu diễn cho các tham số kiểu.

Ví dụ sau hiển thị các phương thức generic có trong interface Collection.

interface Collection<E> {
  public <T> boolean containsAll(Collection<T> c);

  public <T extends E> boolean addAll(Collection<T> c);
}

Đoạn mã trên hiển thị hai phương thức là containsAll() và addAll(). Trong cả hai phương thức này thì loại tham số T chỉ được sử dụng một lần.

Đối với các hàm tạo, các tham số kiểu không được khai báo trong hàm tạo mà lại nằm trong tiêu đề khai báo lớp. Tham số kiểu thực tế được truyền trong khi gọi hàm tạo.

Ví dụ sau trình bày cách khai báo một lớp generic chứa một phương thức khởi tạo generic.

import java.util.*;

class StudPair<T, U> {
  private T name;
  private U rollNumber;

  public StudPair(T nmObj, U rollNo) {
    this.name = nmObj;
    this.rollNumber = rollNo;
  }

  public T displayName() {
    return name;
  }

  public U displayNumber() {
    return rollNumber;
  }

  public static void main(String[] args) {
    StudPair<String, Integer> studObj = new StudPair<>("John", 2);
    System.out.println(studObj.displayName());
    System.out.println(studObj.displayNumber());
  }
}

Trong ví dụ trên, một phương thức khởi tạo generic được khai báo chứa hai tham số kiểu generic được phân tách bằng dấu phẩy. Hình dưới đây hiển thị đầu ra.

Output của lớp StudPair

Chấp nhận các tham số generic

Một khai báo phương thức generic duy nhất có thể được gọi với các đối số thuộc các kiểu khác nhau. Theo loại đối số được truyền vào, trình biên dịch xử lý từng cuộc gọi phương thức. Các phương pháp generic có thể được xác định dựa trên các quy tắc sau:

  • Mỗi phần tham số kiểu bao gồm một hoặc nhiều tham số kiểu cách nhau bằng dấu phẩy. Tham số kiểu là một định danh chỉ định tên kiểu generic.

Lưu ý - Tham số kiểu còn được gọi là biến kiểu.

  • Tất cả các khai báo phương thức generic đều có phần tham số kiểu được phân tách bằng dấu ngoặc nhọn đứng trước kiểu trả về của phương thức.
  • Phần thân của một phương thức generic phải bao gồm các tham số kiểu chỉ đại diện cho các kiểu tham chiếu.

Lưu ý - Phương thức generic được khai báo giống như bất kỳ phương thức nào khác.

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

Ví dụ sau hiển thị một khai báo phương thức generic.

 

public class GenericAcceptReturn {

  public static <E> void displayArray(E[] acceptArray) {
    // Display array elements
    for (E element : acceptArray) {
      System.out.printf("%s ", element);
    }
    System.out.println();
  }

  public static void main(String args[]) {
    // Create arrays of Integer, Double and Character
    Integer[] intArrayObj = {100, 200, 300, 400, 500};
    Double[] doubleArrayObj = {51.1, 52.2, 53.3, 54.4};
    Character[] charArrayObj = {'J', 'A', 'V', 'A'};
    System.out.println("Integer Array contains:");
    displayArray(intArrayObj);
    System.out.println("\nDouble Array contains:");
    displayArray(doubleArrayObj);
    System.out.println("\nCharacter Array contains:");
    displayArray(charArrayObj);
  }
}

Trong đoạn mã trên, displayArray() là một khai báo phương thức generic chấp nhận các loại đối số khác nhau và hiển thị chúng.

Hình dưới biểu thị output của chương trình:

Output của generic displayArrray()

Trả về kiểu generic

Một phương thức cũng có thể trả về kiểu dữ liệu generic. Ví dụ sau hiển thị một phương thức có trả về kiểu generic.

package genericreturntest;import java.util.*;

public class GenericReturnTest {
  public static <T extends Comparable<T>> T maxValueDisplay(T val1, T val2, T val3) {
    T maxValue = val1;
    if (val2.compareTo(val1) > 0) maxValue = val2;
    if (val3.compareTo(maxValue) > 0) maxValue = val3;
    return maxValue;
  }

  /**
   * @param args the command line arguments
   */
  public static void main(String[] args) {
    System.out.println(maxValueDisplay(23, 42, 1));
    System.out.println(maxValueDisplay("apples", "oranges", "pineapple"));
  }
}

Trong ví dụ trên, phương thức compareTo() của lớp Comparator được sử dụng để so sánh các giá trị có thể là int, char, String hoặc bất kỳ kiểu dữ liệu nào. Phương thức compareTo() trả về giá trị lớn nhất. Hình dưới hiển thị kết quả đầu ra.

Generic Return Test

 
 
» Tiếp: Kiểu suy luận (Type Inference)
« Trước: Lớp generic
Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên
Copied !!!