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 4/12
5 phút

Abstract class

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 nhận tiền mặt và thẻ: hình thức nào cũng có số tiền và in biên lai giống nhau, chỉ khác tên hình thức ghi trên biên lai. Một object "thanh toán" chung chung, không rõ là tiền mặt hay thẻ, thì không có nghĩa. Abstract class diễn tả đúng tình huống này.

Khái niệm

🧩 Trừu tượng (abstraction): chỉ đưa ra những gì nơi gọi cần biết, giấu đi chi tiết cách làm.

📐 Abstract class: class không tạo object trực tiếp được, chỉ dùng làm class cha cho các class khác.

✏️ Abstract method: method chỉ có khai báo, không có thân, mọi class con bắt buộc phải override.

Ví dụ

// Main.java
void main() {
    List<Payment> payments = List.of(
        new CashPayment(50000),
        new CardPayment(120000));

    for (Payment p : payments) {
        System.out.println(p.receipt());
    }
}

// Payment.java
abstract class Payment {
    private long amount;

    public Payment(long amount) {
        this.amount = amount;
    }

    public long getAmount() {
        return amount;
    }

    public abstract String kind();

    public String receipt() {
        return kind() + " - " + amount + "đ";
    }
}

// CashPayment.java
class CashPayment extends Payment {
    public CashPayment(long amount) {
        super(amount);
    }

    @Override
    public String kind() {
        return "Tiền mặt";
    }
}

// CardPayment.java
class CardPayment extends Payment {
    public CardPayment(long amount) {
        super(amount);
    }

    @Override
    public String kind() {
        return "Quẹt thẻ";
    }
}
Tiền mặt - 50000đ
Quẹt thẻ - 120000đ
  • abstract class Payment: không viết được new Payment(...).
  • public abstract String kind(); không có thân. Mỗi class con tự ghi tên hình thức thanh toán.
  • receipt() là method bình thường, viết một lần ở class cha và dùng chung.
  • Abstract class vẫn có constructor. Class con gọi nó bằng super(amount).
  • Vòng lặp chỉ biết Payment. Đó là trừu tượng: nơi gọi không cần biết là tiền mặt hay thẻ.
<<abstract>> Payment - amount: long + kind(): * String + receipt(): String CashPayment + kind(): String CardPayment + kind(): String
Payment chỉ khai báo kind(), mỗi class con tự viết thân

So với method thường ở bài trước:

Method thường abstract
Có thân ở class cha có không
Class con phải override không bắt buộc bắt buộc

Thử ngay

Giữ các file của ví dụ. Tạo thêm file dưới đây, và trong Main.java thêm new WalletPayment(80000) làm phần tử thứ ba trong List.of(...):

// WalletPayment.java
class WalletPayment extends Payment {
    public WalletPayment(long amount) {
        super(amount);
    }

    @Override
    public String kind() {
        return "Ví điện tử";
    }
}

Đoán trước khi chạy: dòng biên lai thứ ba in ra gì?

Xem kết quả
Tiền mặt - 50000đ
Quẹt thẻ - 120000đ
Ví điện tử - 80000đ

Dòng thứ ba là Ví điện tử - 80000đ. WalletPayment kế thừa receipt() và tự viết kind(), nên vòng lặp không phải sửa gì.

Lỗi hay gặp

Tạo object từ abstract class. Compiler chặn ngay.

// SAI — lỗi compile: Payment là abstract
var p = new Payment(50000);
// ĐÚNG — tạo từ class con cụ thể
Payment p = new CashPayment(50000);

Class con quên viết abstract method. Mọi abstract method đều phải được override.

// SAI — lỗi compile: thiếu kind()
// Main.java
void main() {
    new BankTransfer(50000);
}

// BankTransfer.java
class BankTransfer extends Payment {
    public BankTransfer(long amount) {
        super(amount);
    }
}
// ĐÚNG
// BankTransfer.java
class BankTransfer extends Payment {
    public BankTransfer(long amount) {
        super(amount);
    }

    @Override
    public String kind() {
        return "Chuyển khoản";
    }
}

Tóm tắt

  • Abstract class là class cha không tạo object trực tiếp được.
  • Abstract method không có thân, class con bắt buộc override.
  • Abstract class vẫn chứa được field, constructor và method bình thường để dùng chung.
  • Trừu tượng: nơi gọi chỉ làm việc với class cha, không cần biết chi tiết từng loại.

Tự kiểm tra

0/3 câu
Câu 1

abstract class Shape { public abstract double area(); } Dòng var s = new Shape(); thì sao?

Câu 2

Khi nào dùng abstract method thay vì method thường?

Câu 3

abstract class Report có abstract method build() và method thường print(). Class SalesReport extends Report cần viết gì tối thiểu?

Đa hìnhInterface

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