VieTopik
Tiếng HànTiếng Anh.NET (C#)Java
  • Góc học tập
Tải app
  • Thư viện
  • Luyện thi
  • Cẩm nang
  • Góc học tập
OOP và thiết kế (Java)Bốn trụ cột OOP
Bài 2/12
5 phút

Kế thừa

Nội dung bài · 5 mục
  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 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;
    }
}
  • book dùng được getName(), getPrice(), describe() dù PhysicalProduct không khai báo chúng. Tất cả nhận lại từ Product.
  • weightGram và shippingFee() là phần riêng, chỉ class con có.
  • Constructor không được kế thừa. super(name, price) gọi constructor của Product để gán name và price, rồi class con gán tiếp weightGram.
  • Field private củ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.
Product - name: String - price: long + getName(): String + getPrice(): long + describe(): String PhysicalProduct - weightGram: int + getWeightGram(): int + shippingFee(): long
PhysicalProduct nhận lại phần của Product, chỉ khai báo thêm phần riêng

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/ebook

Chạ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âu
Câu 1

Class 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?

Câu 2

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?

Câu 3

Trường hợp nào dùng kế thừa là hợp lý?

Đóng góiĐa hình

Nội dung bài

  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt