Chuỗi gọi hàm khởi tạo
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 23 trên 87.
Gọi nối tiếp hàm khởi tạo (constructor chaining) là quá trình gọi một hàm khởi tạo từ một hàm khởi tạo khác. Kỹ thuật này giúp tránh lặp lại code khi một lớp có nhiều hàm khởi tạo hoặc khi làm việc với các hệ thống phân cấp kế thừa.
Trong cùng một lớp, bạn có thể gọi nối tiếp các hàm khởi tạo bằng this(). Cách này cho phép bạn có một hàm khởi tạo “chính” xử lý mọi việc, còn các hàm khởi tạo khác chỉ chuyển tiếp đến hàm đó:
public class Rectangle {
private int width;
private int height;
public Rectangle() {
this(1, 1); // Gọi hàm khởi tạo có hai tham số
}
public Rectangle(int size) {
this(size, size); // Tạo một hình vuông
}
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
}Trong kế thừa, việc gọi chuỗi hàm khởi tạo diễn ra tự động. Khi bạn tạo một đối tượng của lớp con, Java gọi hàm khởi tạo của lớp cha trước bằng super(). Nếu bạn không gọi rõ ràng super(), Java tự động chèn super() (phiên bản không có đối số):
public class Animal {
private String name;
public Animal(String name) {
this.name = name;
System.out.println("Animal constructor");
}
}
public class Dog extends Animal {
private String breed;
public Dog(String name, String breed) {
super(name); // Phải là dòng đầu tiên
this.breed = breed;
System.out.println("Dog constructor");
}
}Việc tạo new Dog("Buddy", "Labrador") sẽ in ra "Animal constructor" trước, rồi đến "Dog constructor". Nhờ vậy, các lớp cha luôn được khởi tạo đúng cách trước khi lớp con thêm phần thiết lập riêng.
Thử thách
DễHãy xây dựng một hệ thống đặt hàng sản phẩm để minh họa cách gọi chuỗi hàm khởi tạo trong cùng một lớp và qua hệ thống kế thừa. Bạn sẽ thấy cách this() gọi chuỗi hàm khởi tạo trong cùng lớp, còn super() gọi hàm khởi tạo của lớp cha.
Bạn sẽ tạo ba tệp để sắp xếp code:
Product.java: Tạo một lớp cha đại diện cho mọi sản phẩm trong cửa hàng. Lớp này cần có:- Các trường private cho
name(String) vàprice(double) - Một hàm khởi tạo chính nhận cả tên và giá, khởi tạo các trường, rồi in ra:
Product constructor: [name] - Một hàm khởi tạo thứ hai chỉ nhận tên và gọi chuỗi hàm khởi tạo chính bằng
this(name, 0.0)để đặt giá mặc định là 0.0 - Các phương thức
getName()vàgetPrice()để truy cập các trường
- Các trường private cho
Electronics.java: Tạo một lớp con kế thừa Product và bổ sung thông tin bảo hành:- Một trường private cho
warrantyYears(int) - Một hàm khởi tạo chính nhận tên, giá và warrantyYears, dùng
super(name, price)để khởi tạo lớp cha, sau đó đặt thời hạn bảo hành và in ra:Electronics constructor: [warrantyYears] year warranty - Một hàm khởi tạo thứ hai chỉ nhận tên và giá, gọi chuỗi hàm khởi tạo chính bằng
this(name, price, 1)để đặt thời hạn bảo hành mặc định là 1 năm - Một hàm khởi tạo thứ ba chỉ nhận tên, gọi chuỗi hàm khởi tạo thứ hai bằng
this(name, 0.0) - Một phương thức
getDetails()trả về:[name] - $[price] ([warrantyYears] year warranty)
- Một trường private cho
Main.java: Minh họa cách gọi chuỗi hàm khởi tạo. Bạn sẽ nhận ba đầu vào: tên sản phẩm (String), giá (double) và số năm bảo hành (int). Tạo một đối tượng Electronics bằng cả ba tham số, rồi in ra kết quả củagetDetails().
Bạn sẽ nhận ba đầu vào: tên sản phẩm, giá và số năm bảo hành.
Định dạng giá trong getDetails() để hiển thị 2 chữ số thập phân bằng String.format("%.2f", price). Hãy theo dõi kỹ đầu ra, bạn sẽ thấy các thông báo của hàm khởi tạo xuất hiện theo thứ tự, cho thấy chuỗi gọi chạy từ lớp cha đến lớp con!
Tự làm thử
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Đọc các đầu vào
String name = scanner.nextLine();
double price = scanner.nextDouble();
int warrantyYears = scanner.nextInt();
// TODO: Tạo đối tượng Electronics bằng cả ba tham số
// TODO: In ra kết quả của getDetails()
}
}
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