Phương thức tổng quát
Thuộc phần Lập trình hướng đối tượng trong hành trình Java của Coddy. Bài học 55 trên 87.
Trong khi các lớp tổng quát cho phép cả lớp hoạt động với nhiều kiểu khác nhau, đôi khi bạn chỉ cần một phương thức tổng quát. Phương thức tổng quát khai báo tham số kiểu riêng, độc lập với các kiểu tổng quát ở cấp lớp.
Tham số kiểu xuất hiện trước kiểu trả về trong chữ ký phương thức:
public class Utility {
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
}
String[] names = {"Alice", "Bob"};
Integer[] numbers = {1, 2, 3};
Utility.printArray(names); // Chạy được với String[]
Utility.printArray(numbers); // Chạy được với Integer[]Hãy chú ý đến <T> nằm giữa các từ bổ nghĩa và kiểu trả về. Phần này khai báo T là tham số kiểu của riêng phương thức này. Trình biên dịch suy ra kiểu thực tế từ các đối số bạn truyền vào.
Các phương thức tổng quát cũng có thể trả về kiểu tổng quát:
public static <T> T getFirst(T[] array) {
if (array.length > 0) {
return array[0];
}
return null;
}
String first = getFirst(new String[]{"a", "b"}); // Trả về "a"Bạn có thể dùng nhiều tham số kiểu khi cần:
public static <K, V> void printPair(K key, V value) {
System.out.println(key + ": " + value);
}
printPair("Age", 25); // String và Integer
printPair(1, "First"); // Integer và StringCác phương thức tổng quát đặc biệt hữu ích trong những lớp tiện ích, nơi bạn cần các thao tác linh hoạt, có thể tái sử dụng mà không cần tạo lớp tổng quát.
Thử thách
DễHãy xây dựng một bộ công cụ tiện ích thể hiện tính linh hoạt của các phương thức tổng quát. Bạn sẽ tạo một lớp có các phương thức có thể tái sử dụng và hoạt động với mọi kiểu dữ liệu, qua đó cho thấy phương thức tổng quát có thể tồn tại độc lập với lớp tổng quát.
Bạn sẽ sắp xếp code trong hai tệp:
ArrayUtils.java: Tạo một lớp tiện ích chứa các phương thức tổng quát để làm việc với mảng. Lớp của bạn cần có ba phương thức tổng quát tĩnh:getLast- Một phương thức tổng quát nhận một mảng kiểuTvà trả về phần tử cuối cùng. Nếu mảng rỗng, hãy trả vềnull.swap- Một phương thức tổng quát nhận một mảng kiểuTvà hai chỉ số nguyên, sau đó hoán đổi các phần tử ở những vị trí đó. Phương thức này không trả về gì cả.printWithLabel- Một phương thức tổng quát có hai tham số kiểuKvàV. Phương thức nhận một nhãn kiểuKvà một giá trị kiểuV, sau đó in chúng theo định dạng:[label]: [value]Main.java: Hãy sử dụng các phương thức tổng quát! Bạn sẽ nhận bốn đầu vào: hai từ (Strings) và hai số (số nguyên).Đầu tiên, tạo một mảng
String[]chứa cả hai từ. DùnggetLastđể lấy phần tử cuối cùng rồi in:Last word: [result]Tiếp theo, tạo một mảng
Integer[]chứa cả hai số. Gọiswapđể hoán đổi các phần tử ở chỉ số 0 và 1, rồi in:After swap: [first], [second]Cuối cùng, hãy minh họa phương thức tổng quát có hai tham số bằng cách gọi
printWithLabelhai lần:- Một lần với từ đầu tiên làm nhãn và số đầu tiên làm giá trị
- Một lần với số đầu tiên làm nhãn và từ thứ hai làm giá trị
Bạn sẽ nhận bốn đầu vào theo thứ tự: từ đầu tiên, từ thứ hai, số đầu tiên, số thứ hai.
Hãy chú ý cách mỗi phương thức khai báo (declare) (khai báo) tham số kiểu riêng bằng <T> hoặc <K, V> trước kiểu trả về. Trình biên dịch suy ra các kiểu thực tế từ những đối số bạn truyền vào, nên bạn không cần chỉ định chúng khi gọi phương thức!
Tự làm thử
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Đọc dữ liệu đầu vào
String firstWord = scanner.nextLine();
String secondWord = scanner.nextLine();
int firstNumber = scanner.nextInt();
int secondNumber = scanner.nextInt();
// TODO: Tạo mảng String[] chứa cả hai từ
// TODO: Dùng ArrayUtils.getLast để lấy phần tử cuối cùng
// In ra: "Last word: [result]"
// TODO: Tạo mảng Integer[] chứa cả hai số
// TODO: Gọi ArrayUtils.swap để hoán đổi các phần tử ở chỉ số 0 và 1
// In ra: "After swap: [first], [second]"
// TODO: Gọi ArrayUtils.printWithLabel với firstWord làm nhãn và firstNumber làm giá trị
// TODO: Gọi ArrayUtils.printWithLabel với firstNumber làm nhãn và secondWord làm giá trị
}
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Kiến thức cơ bản về lập trình hướng đối tượng
Tệp bên ngoàiGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTừ khóa thisPhương thứcTrường (thuộc tính)Phương thức khởi tạoNạp chồng phương thức khởi tạoÔn tập: Máy tính đơn giản4Kế thừa
Kế thừa cơ bản (extends)Từ khóa superGhi đè phương thức (@Override)Chuỗi gọi hàm khởi tạoLớp ObjectKế thừa đơn và đa cấpVì sao không hỗ trợ kế thừa nhiều lớpÔn tập: Phân cấp lớp Employee7Phương thức đặc biệt và lớp Object
Phương thức toString()equals() và hashCode()Phương thức clone()compareTo() và ComparableGiao diện ComparatorÔn tập: sắp xếp tùy chỉnh2Bộ điều chỉnh quyền truy cập và đóng gói
Tổng quan về các mức truy cậpPhương thức getter và setterẨn thông tinTừ khóa finalÔn tập: Trình quản lý tài khoản ngân hàng5Tính đa hình
Kiến thức cơ bản về nạp chồng phương thứcGhi đè phương thức (thời gian chạy)Chuyển kiểu lên và chuyển kiểu xuốngToán tử instanceofLớp và phương thức trừu tượngÔn tập: máy tính hình học8Khái niệm OOP nâng cao
Kết hợp và kế thừaKết tập và hợp thànhLớp bên trong, lớp lồng nhau và lớp ẩn danhKiểu enum và phương thức enumBản ghi (Java 16+)Lớp sealed (Java 17+)3Thuộc tính lớp và thành viên tĩnh
Biến của instance và biến tĩnhPhương thức tĩnhKhối tĩnhHằng số (static final)Ôn tập: bộ đếm và tiện ích6Giao diện và lớp trừu tượng
Giới thiệu về giao diệnTriển khai giao diệnTriển khai nhiều giao diệnPhương thức mặc định và tĩnh trong giao diệnLớp trừu tượng và giao diệnGiao diện hàmÔn tập: hệ thống thanh toán9Kiểu tổng quát
Giới thiệu về kiểu tổng quátLớp tổng quátPhương thức tổng quátTham số kiểu có giới hạnKý tự đại diện (?, extends, super)Ôn tập: vùng chứa tổng quát12Mẫu thiết kế, phần 2
Mẫu CommandMẫu AdapterMẫu DecoratorMẫu Template MethodMẫu StateMẫu CompositeMẫu IteratorTự luyện tập: Trình biên dịch Java online