
Chào các gen Z mê code, hôm nay anh Creyt sẽ cùng các em "độ" lại kiến thức OOP với một khái niệm cực kỳ "bá đạo": Child Class trong Java. Nghe tên đã thấy có gì đó thân thuộc rồi đúng không? Cứ bình tĩnh, anh Creyt sẽ biến nó thành món ăn dễ nuốt nhất!
Child Class là gì mà "hot" vậy?
Để dễ hình dung, các em cứ tưởng tượng thế này: Chúng ta có một cái case PC cơ bản (đây là Parent Class hay Super Class). Nó có đủ các cổng USB, chỗ lắp mainboard, nguồn điện... nói chung là những thứ "cốt lõi" nhất của một cái máy tính. Giờ em muốn build một con PC gaming xịn sò, em đâu cần phải tự "chế" lại từ con ốc vít đúng không? Em sẽ lấy cái case cơ bản đó làm nền, rồi thêm thắt vào đó những linh kiện "khủng" hơn: card đồ họa RTX series mới nhất, RAM tốc độ cao, ổ cứng SSD NVMe, và cả dàn đèn RGB lung linh nữa. Cái "con PC gaming xịn sò" mà em vừa độ lên chính là Child Class (hay Sub Class) của cái case PC cơ bản kia.
Nói cách khác, Child Class là một class kế thừa tất cả các thuộc tính (fields) và phương thức (methods) từ một Parent Class có sẵn. Sau đó, nó có thể mở rộng thêm các thuộc tính và phương thức mới của riêng mình, hoặc ghi đè (override) các phương thức đã kế thừa để thay đổi hành vi cho phù hợp với mục đích sử dụng cụ thể của nó. Mục đích chính là: tái sử dụng code và mở rộng tính năng một cách có tổ chức.
Code Ví Dụ Minh Hoạ: "Độ" Xe Hơi Cùng Creyt
Anh em mình cùng "độ" xe hơi nhé. Chúng ta sẽ có một class Car cơ bản, sau đó "độ" thành SportsCar.
// Bước 1: Tạo Parent Class (Super Class) - Cái khung xe cơ bản
class Car {
String brand;
String model;
int year;
public Car(String brand, String model, int year) {
this.brand = brand;
this.model = model;
this.year = year;
}
public void startEngine() {
System.out.println(brand + " " + model + "'s engine started. Vroom vroom!");
}
public void accelerate() {
System.out.println(brand + " " + model + " is accelerating.");
}
public void displayInfo() {
System.out.println("Brand: " + brand + ", Model: " + model + ", Year: " + year);
}
}
// Bước 2: Tạo Child Class (Sub Class) - "Độ" thành xe thể thao
class SportsCar extends Car {
int topSpeed;
String spoilerType;
// Constructor của SportsCar phải gọi constructor của Parent Class (Car)
public SportsCar(String brand, String model, int year, int topSpeed, String spoilerType) {
super(brand, model, year); // Gọi constructor của Car
this.topSpeed = topSpeed;
this.spoilerType = spoilerType;
}
// Thêm phương thức mới đặc trưng cho SportsCar
public void activateTurbo() {
System.out.println(brand + " " + model + "'s turbo engaged! Maximum thrust!");
}
// Ghi đè (Override) phương thức accelerate() từ Car để có hành vi khác
@Override // Annotation này giúp kiểm tra xem bạn có override đúng không
public void accelerate() {
System.out.println(brand + " " + model + " is accelerating like a rocket! SCREECH!");
}
// Ghi đè phương thức displayInfo() để hiển thị thêm thông tin của SportsCar
@Override
public void displayInfo() {
super.displayInfo(); // Gọi phương thức displayInfo() của Parent Class trước
System.out.println("Top Speed: " + topSpeed + " mph, Spoiler Type: " + spoilerType);
}
}
// Bước 3: Thử nghiệm trong phương thức main
public class InheritanceDemo {
public static void main(String[] args) {
System.out.println("--- Car Thường ---");
Car regularCar = new Car("Honda", "Civic", 2022);
regularCar.displayInfo();
regularCar.startEngine();
regularCar.accelerate();
System.out.println("\n--- Sports Car ""Độ"" ---");
SportsCar ferrari = new SportsCar("Ferrari", "488 GTB", 2023, 205, "Carbon Fiber");
ferrari.displayInfo(); // Gọi phương thức đã override
ferrari.startEngine(); // Kế thừa từ Car
ferrari.accelerate(); // Gọi phương thức đã override
ferrari.activateTurbo(); // Phương thức mới của SportsCar
}
}
Giải thích chi tiết:
class SportsCar extends Car: Từ khóaextendschính là "phép thuật" để biếnSportsCarthành Child Class củaCar. Nó báo hiệu rằngSportsCarsẽ kế thừa mọi thứ từCar.super(brand, model, year);: Trong constructor củaSportsCar, chúng ta dùngsuper()để gọi constructor tương ứng của Parent Class (Car). Điều này đảm bảo rằng các thuộc tính củaCarđược khởi tạo đúng cách trước khiSportsCarthêm vào những "đồ chơi" của riêng nó.@Override: Đây là mộtannotation(chú thích) cực kỳ hữu ích. Nó không bắt buộc về mặt cú pháp nhưng rất nên dùng. Nó giúp compiler kiểm tra xem bạn có thực sự ghi đè một phương thức có sẵn trong Parent Class hay không. Nếu bạn gõ sai tên phương thức hoặc sai tham số, compiler sẽ báo lỗi ngay, tránh được những bug "khoai" sau này.super.displayInfo();: Khi bạn ghi đè một phương thức nhưng vẫn muốn giữ lại một phần logic của Parent Class, bạn có thể dùngsuper.tenPhuongThuc()để gọi phương thức đó từ Parent Class.

Mẹo (Best Practices) để "chiến" Child Class hiệu quả
- "IS-A" Relationship: Chỉ dùng Child Class khi có mối quan hệ "Là một" (IS-A) rõ ràng. Ví dụ:
SportsCar IS-A Car(Xe thể thao LÀ MỘT Xe hơi). Đừng bao giờ dùng khi mối quan hệ chỉ là "HAS-A" (Có một). Ví dụ:Car HAS-A Engine(Xe hơi CÓ MỘT Động cơ) thìEnginenên là một thuộc tính củaCar, không phải Child Class củaCar. - Tránh "chuỗi" kế thừa quá sâu: Một chuỗi kế thừa dài (A -> B -> C -> D) có thể làm code khó hiểu và khó bảo trì. Hãy giữ cho các cấp độ kế thừa ở mức vừa phải, thường là 1-2 cấp là đủ. Quá nhiều cấp sẽ làm "ghánh nặng" cho các class con.
- Ưu tiên Composition & Interface: Đôi khi, thay vì dùng kế thừa, bạn nên cân nhắc Composition (ghép các đối tượng lại với nhau) hoặc Interface (định nghĩa hợp đồng hành vi). Chúng thường linh hoạt hơn và giúp tránh được một số vấn đề của kế thừa (như "banana-gorilla problem" - bạn muốn quả chuối nhưng lại phải mang theo cả con khỉ và khu rừng).
- Polymorphism là "bạn thân" của kế thừa: Kế thừa cho phép bạn dùng một đối tượng Child Class ở nơi cần đối tượng Parent Class. Ví dụ:
Car myVehicle = new SportsCar(...). Đây chính là đa hình (polymorphism), giúp code của bạn linh hoạt và dễ mở rộng hơn rất nhiều.
Ứng dụng thực tế: Child Class ở khắp mọi nơi!
Child Class không phải là khái niệm "trên trời" mà nó hiện diện trong hầu hết các ứng dụng bạn dùng hàng ngày:
- Android Development: Trong Android, các UI component như
Button,TextView,ImageViewđều là Child Class củaView.Activitylà Child Class củaContextThemeWrapper. Bạn kế thừa chúng để thêm hành vi riêng cho ứng dụng của mình. - Java Swing/JavaFX: Tương tự, các thành phần giao diện người dùng như
JButton,JTextFieldđều kế thừa từJComponenthoặcComponent. - Các Framework lớn (Spring, Hibernate): Rất nhiều thành phần cốt lõi của các framework này được thiết kế để bạn có thể kế thừa và tùy chỉnh, ví dụ như tạo các
Controllertrong Spring MVC. - Thư viện đồ họa, game: Các đối tượng trong game (nhân vật, kẻ thù, vật phẩm) thường kế thừa từ một class
GameObjectcơ bản để chia sẻ các thuộc tính chung như vị trí, vận tốc.
Creyt đã từng "test" và lời khuyên chân thành
Anh Creyt đã từng "nghiện" kế thừa đến mức tạo ra những cây kế thừa sâu hoắm, cuối cùng thì tự mình "vật vã" sửa bug vì một thay đổi nhỏ ở class cha lại ảnh hưởng đến hàng chục class con. Bài học rút ra là: dùng kế thừa có chọn lọc và có mục đích rõ ràng.
Khi nào nên dùng Child Class?
- Khi bạn muốn tái sử dụng code: Có một tập hợp các thuộc tính và hành vi chung mà nhiều đối tượng sẽ chia sẻ.
- Khi bạn muốn mở rộng hoặc chuyên biệt hóa: Bạn có một khái niệm chung và muốn tạo ra các phiên bản cụ thể hơn của nó (như
CarvàSportsCar). - Khi bạn muốn tận dụng Polymorphism: Để viết code linh hoạt hơn, có thể xử lý các đối tượng khác nhau một cách thống nhất thông qua một kiểu dữ liệu chung (kiểu của Parent Class).
Tóm lại: Child Class là một công cụ cực mạnh trong OOP, giúp code của bạn gọn gàng, dễ mở rộng. Nhưng cũng như mọi công cụ mạnh mẽ khác, hãy dùng nó một cách thông minh và có trách nhiệm nhé các "đệ" của Creyt!
Nếu có câu hỏi gì, đừng ngần ngại "ping" anh Creyt nhé!
Thuộc Series: Java – OOP
Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!