Kế thừa đơn và đa cấp
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 25 trên 87.
Đến giờ, chúng ta đã thấy các lớp kế thừa trực tiếp từ một lớp cha. Nhưng cấu trúc kế thừa có thể khác nhau tùy vào mối quan hệ giữa các lớp. Hãy cùng tìm hiểu hai kiểu chính: kế thừa đơn và kế thừa đa cấp.
Kế thừa đơn là cách kế thừa mà chúng ta đang dùng. Một lớp (class) chỉ trực tiếp kế thừa từ đúng một lớp cha:
public class Animal { }
public class Dog extends Animal { }
public class Cat extends Animal { }Ở đây, cả Dog và Cat đều kế thừa từ Animal, nhưng chúng không kế thừa lẫn nhau. Mỗi lớp con có một lớp cha trực tiếp.
Kế thừa nhiều cấp tạo ra một chuỗi trong đó một lớp kế thừa từ lớp khác, rồi chính lớp đó lại kế thừa từ một lớp khác:
public class Animal {
public void eat() {
System.out.println("Eating");
}
}
public class Mammal extends Animal {
public void breathe() {
System.out.println("Breathing");
}
}
public class Dog extends Mammal {
public void bark() {
System.out.println("Barking");
}
}Trong chuỗi kế thừa này, Dog kế thừa từ Mammal, còn Mammal kế thừa từ Animal. Đối tượng Dog có thể truy cập tất cả phương thức trong toàn bộ chuỗi:
Dog dog = new Dog();
dog.eat(); // Từ Animal
dog.breathe(); // Từ Mammal
dog.bark(); // Từ DogHãy nhớ rằng Object đứng ở đầu mọi chuỗi kế thừa. Vì vậy, Dog thực tế có bốn cấp: Object -> Animal -> Mammal -> Dog. Quá trình gọi nối tiếp các hàm khởi tạo (constructor) đi qua tất cả các cấp này khi tạo một đối tượng mới.
Thử thách
DễHãy xây dựng một hệ thống phân cấp phương tiện giao thông để minh họa cả kế thừa đơn và kế thừa đa cấp. Bạn sẽ tạo một chuỗi các lớp, trong đó mỗi cấp bổ sung khả năng mới, qua đó cho thấy các phương thức được kế thừa qua nhiều cấp như thế nào.
Bạn sẽ sắp xếp code trong bốn tệp:
Vehicle.java: Tạo lớp cơ sở ở cấp cao nhất trong hệ thống phân cấp. Mỗi phương tiện cần có:- Một trường private dành cho
brand(String) - Một hàm khởi tạo nhận brand
- Một phương thức
getBrand()trả về brand - Một phương thức
move()in ra:[brand] is moving
- Một trường private dành cho
LandVehicle.java: Tạo một lớp mở rộng Vehicle, đại diện cho cấp giữa trong chuỗi kế thừa đa cấp. Phương tiện trên mặt đất bổ sung các hành vi đặc thù trên mặt đất:- Một trường private dành cho
wheels(int) - Một hàm khởi tạo nhận brand và wheels, dùng
super(brand)cho phần của lớp cha - Một phương thức
getWheels()trả về số bánh xe - Một phương thức
honk()in ra:[brand] honks!
- Một trường private dành cho
Car.java: Tạo một lớp mở rộng LandVehicle, hoàn thiện chuỗi kế thừa gồm ba cấp. Ô tô bổ sung các tính năng chuyên biệt:- Một trường private dành cho
model(String) - Một hàm khởi tạo nhận brand, wheels và model, dùng
super(brand, wheels) - Một phương thức
getModel()trả về model - Một phương thức
displayInfo()in ra:[brand] [model] with [wheels] wheels
- Một trường private dành cho
Main.java: Minh họa cách một đối tượng Car có thể truy cập các phương thức từ cả ba cấp trong hệ thống phân cấp. Bạn sẽ nhận ba đầu vào: brand (String), wheels (int) và model (String). Tạo một Car và gọi các phương thức sau theo thứ tự:move(), được kế thừa từ Vehicle (lớp ông bà)honk(), được kế thừa từ LandVehicle (lớp cha)displayInfo(), được định nghĩa ngay trong Car
Bạn sẽ nhận ba đầu vào: tên brand, số bánh xe và tên model.
Đầu ra cần có ba dòng, minh họa cách đối tượng Car có thể sử dụng các phương thức từ mọi cấp trong chuỗi kế thừa, từ Vehicle ở cấp cao nhất cho đến lớp của chính nó!
Tự làm thử
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Đọc các giá trị đầu vào
String brand = scanner.nextLine();
int wheels = scanner.nextInt();
scanner.nextLine(); // đọc bỏ ký tự xuống dòng
String model = scanner.nextLine();
// TODO: Tạo đối tượng Car với các giá trị đầu vào
// TODO: Gọi move(), kế thừa từ Vehicle (lớp ông)
// TODO: Gọi honk(), kế thừa từ LandVehicle (lớp cha)
// TODO: Gọi displayInfo(), được định nghĩa trong chính Car
}
}
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