Kế thừa
Nội dung bài · 5 mục
- 1.Khái niệm
- 2.Ví dụ
- 3.Thử ngay
- 4.Lỗi hay gặp
- 5.Tóm tắt
Cửa hàng bán sách giấy và ebook. Cả hai đều có tên, có giá, có cùng cách hiển thị. Viết hai class riêng thì phần chung bị lặp lại, sửa một chỗ lại phải nhớ sửa chỗ kia. Kế thừa giải quyết đúng việc này.
Khái niệm
🧬 Kế thừa (inheritance): class con nhận lại field và method của class cha, rồi thêm phần riêng của mình.
👪 Class cha, class con (superclass, subclass): class được kế thừa là class cha, class kế thừa nó là class con, khai báo bằng class Con extends Cha.
Kế thừa chỉ đúng khi class con là một loại của class cha. Sách giấy là một
loại sản phẩm, nên PhysicalProduct extends Product hợp lý.
Ví dụ
// Main.java
void main() {
var book = new PhysicalProduct(
"Sách Java", 150000, 800);
System.out.println(book.describe());
System.out.println(book.shippingFee());
}
// Product.java
class Product {
private String name;
private long price;
public Product(String name, long price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public long getPrice() {
return price;
}
public String describe() {
return name + " - " + price + "đ";
}
}
// PhysicalProduct.java
class PhysicalProduct extends Product {
private int weightGram;
public PhysicalProduct(String name, long price,
int weightGram) {
super(name, price);
this.weightGram = weightGram;
}
public int getWeightGram() {
return weightGram;
}
public long shippingFee() {
return weightGram * 10;
}
}bookdùng đượcgetName(),getPrice(),describe()dùPhysicalProductkhông khai báo chúng. Tất cả nhận lại từProduct.weightGramvàshippingFee()là phần riêng, chỉ class con có.- Constructor không được kế thừa.
super(name, price)gọi constructor củaProductđể gánnamevàprice, rồi class con gán tiếpweightGram. - Field
privatecủa cha không dùng thẳng được trong class con. Class con đọc chúng qua getter, nhưgetName(). - Một class chỉ kế thừa được một class cha.
Thử ngay
Giữ các file của ví dụ. Thay main trong Main.java bằng đoạn dưới đây, rồi
tạo thêm file DigitalProduct.java:
// Main.java
void main() {
var ebook = new DigitalProduct(
"Ebook Java", 90000, "https://shop.vn/ebook");
System.out.println(ebook.describe());
System.out.println(ebook.getDownloadUrl());
}
// DigitalProduct.java
class DigitalProduct extends Product {
private String downloadUrl;
public DigitalProduct(String name, long price,
String downloadUrl) {
super(name, price);
this.downloadUrl = downloadUrl;
}
public String getDownloadUrl() {
return downloadUrl;
}
}Đoán trước khi chạy: DigitalProduct không hề khai báo describe(). Dòng
ebook.describe() có chạy được không, và in ra gì?
Xem kết quả
Ebook Java - 90000đ
https://shop.vn/ebookChạy được. DigitalProduct kế thừa describe() từ Product, nên phần chung
chỉ viết một lần ở class cha.
Lỗi hay gặp
Quên gọi super(...). Không gọi thì Java tự gọi constructor rỗng của
class cha. Class cha không có constructor rỗng thì compiler không biết tạo
phần cha bằng cách nào (như bài Getter, setter và constructor: có constructor
nhận tham số thì không còn constructor rỗng).
// SAI — lỗi compile: thiếu super(name, price)
// Main.java
void main() {
new GiftCard("Thẻ quà", 100000);
}
// GiftCard.java
class GiftCard extends Product {
public GiftCard(String name, long price) {
}
}// ĐÚNG
// GiftCard.java
class GiftCard extends Product {
public GiftCard(String name, long price) {
super(name, price);
}
}Kế thừa chỉ để dùng lại code. Khách hàng không phải là một địa chỉ, nên
Customer extends Address là sai, dù làm vậy giúp Customer có sẵn
street.
// SAI — khách hàng không "là một" địa chỉ
// Customer.java
class Customer extends Address {
private String name = "";
}
// Address.java
class Address {
private String street = "";
}// ĐÚNG — khách hàng "có một" địa chỉ
// Customer.java
class Customer {
private String name = "";
private Address address = new Address();
}
// Address.java
class Address {
private String street = "";
}Tóm tắt
class Con extends Cha: class con nhận lại field và method của class cha, rồi thêm phần riêng.- Constructor không được kế thừa. Class con gọi constructor của cha bằng
super(...). - Một class chỉ có một class cha.
- Chỉ kế thừa khi con là một loại của cha.
Tự kiểm tra
0/3 câuClass Employee có method getInfo(). Class Manager extends Employee không khai báo method nào thêm. Gọi new Manager(...).getInfo() thì sao?
Class Vehicle chỉ có constructor Vehicle(String plate). Class Truck extends Vehicle viết constructor Truck(String plate) { } mà không gọi super(plate). Chuyện gì xảy ra?
Trường hợp nào dùng kế thừa là hợp lý?