Lab 05 — Abstract, kế thừa, đa hình

LAB 05 — GIẢI CHI TIẾT (LỚP TRỪU TƯỢNG, KẾ THỪA, ĐA HÌNH, BƯU PHẨM)

Nguồn: lab05.doc (Bài thực hành số 05). Bám lý thuyết buổi 11 và 12. Đây là lab "đỉnh" của môn: dùng đồng thời abstract + kế thừa + đa hình + mảng đối tượng.

0. Bản đồ bài làm

Phần Lớp Quan hệ Tệp
Chính DiemHP (abstract) cha DiemHP.java
Chính HPLyThuyet IS-A DiemHP HPLyThuyet.java
Chính HPThucHanh IS-A DiemHP HPThucHanh.java
Chính SinhVien HAS-A 2 DiemHP SinhVien.java
Chạy — — QuanLyHP.java
Mở rộng HPDoAn IS-A DiemHP HPDoAn.java
Ở nhà BuuPham (abstract) cha BuuPham.java
Ở nhà Thu, BuuKien IS-A BuuPham Thu.java, BuuKien.java
Ở nhà ThungThu HAS-A mảng ThungThu.java

PHẦN 1 — DiemHP, HPLyThuyet, HPThucHanh

0. Đề bài

DiemHP là lớp trừu tượng dùng làm cơ sở tính điểm: có tenHP, soTinChi, phương thức trừu tượng tinhDiem(). HPLyThuyet kế thừa, có chuyenCan, giuaKy, cuoiKy (0..10), điểm = cc*0.1 + gk*0.2 + ck*0.7. HPThucHanh kế thừa, có db1, db2, db3 (0..10), điểm = trung bình cộng 3 bài.

1. Yêu cầu ẩn

2. Input → Output

Lớp Dữ liệu Công thức
HPLyThuyet cc, gk, ck 0.1·cc + 0.2·gk + 0.7·ck
HPThucHanh db1, db2, db3 (db1 + db2 + db3) / 3
SinhVien hp1, hp2 (d1·tc1 + d2·tc2)/(tc1 + tc2)

3. Thiết kế

                       DiemHP  «abstract»
                 - tenHP : String
                 - soTinChi : int
                 + DiemHP(tenHP, tc)
                 + tinhDiem() : double   «abstract»
                          ^
              +-----------+-----------+
              |                       |
        HPLyThuyet                HPThucHanh
   - chuyenCan, giuaKy,      - db1, db2, db3
     cuoiKy                  + tinhDiem()
   + tinhDiem()

                    SinhVien
              - hoTen : String
              - hp1, hp2 : DiemHP      <- kiểu CHA, object CON (da hinh)
              + tinhDTB() : double

Quyết định thiết kế:

  1. abstract class (không phải interface) vì cần chia sẻ code + trạng thái (tenHP, soTinChi, toString).
  2. SinhVien khai báo DiemHP hp1 chứ không phải HPLyThuyet → nhận được cả hai loại, và mở rộng thêm HPDoAn mà không sửa SinhVien.
  3. Không dùng instanceof để tính điểm — dùng hp1.tinhDiem() (đa hình).

4. Code từng bước

Bước 1 — lớp trừu tượng DiemHP.

public abstract class DiemHP {
    private String tenHP;
    private int soTinChi;

    public DiemHP(String tenHP, int soTinChi) {
        this.tenHP = tenHP;
        setSoTinChi(soTinChi);
    }

    public abstract double tinhDiem();      // KHONG co than

Bước 2 — HPLyThuyet gọi super và override.

public class HPLyThuyet extends DiemHP {
    private double chuyenCan, giuaKy, cuoiKy;

    public HPLyThuyet(String tenHP, int tc,
                      double cc, double gk, double ck) {
        super(tenHP, tc);                   // dong dau tien
        this.chuyenCan = cc; this.giuaKy = gk; this.cuoiKy = ck;
    }

    @Override
    public double tinhDiem() {
        return chuyenCan * 0.1 + giuaKy * 0.2 + cuoiKy * 0.7;
    }
}

Bước 3 — HPThucHanh.

@Override
public double tinhDiem() {
    return (db1 + db2 + db3) / 3;
}

Bước 4 — toString dùng chung ở lớp cha (lợi ích của abstract class).

@Override
public String toString() {
    double d = Math.round(tinhDiem() * 100) / 100.0;   // goi da hinh
    return tenHP + " (" + soTinChi + " TC): " + d;
}

Lưu ý: toString gọi tinhDiem() trừu tượng — khi chạy, nó tự chọn bản của lớp con. Đây là đa hình ngay trong lớp cha.

5. Lời giải hoàn chỉnh

// ===== DiemHP.java =====
public abstract class DiemHP {
    private String tenHP;
    private int soTinChi;

    public DiemHP(String tenHP, int soTinChi) {
        this.tenHP = tenHP;
        setSoTinChi(soTinChi);
    }

    public String getTenHP() { return tenHP; }

    public int getSoTinChi() { return soTinChi; }

    public void setSoTinChi(int tc) {
        if (tc >= 1 && tc <= 4) this.soTinChi = tc;
    }

    public abstract double tinhDiem();

    @Override
    public String toString() {
        double d = Math.round(tinhDiem() * 100) / 100.0;
        return tenHP + " (" + soTinChi + " TC): " + d;
    }
}
// ===== HPLyThuyet.java =====
public class HPLyThuyet extends DiemHP {
    private double chuyenCan, giuaKy, cuoiKy;

    public HPLyThuyet(String tenHP, int soTinChi,
                      double chuyenCan, double giuaKy, double cuoiKy) {
        super(tenHP, soTinChi);
        setChuyenCan(chuyenCan);
        setGiuaKy(giuaKy);
        setCuoiKy(cuoiKy);
    }

    public void setChuyenCan(double d) { if (d >= 0 && d <= 10) chuyenCan = d; }
    public void setGiuaKy(double d)    { if (d >= 0 && d <= 10) giuaKy = d; }
    public void setCuoiKy(double d)    { if (d >= 0 && d <= 10) cuoiKy = d; }

    @Override
    public double tinhDiem() {
        return chuyenCan * 0.1 + giuaKy * 0.2 + cuoiKy * 0.7;
    }
}
// ===== HPThucHanh.java =====
public class HPThucHanh extends DiemHP {
    private double db1, db2, db3;

    public HPThucHanh(String tenHP, int soTinChi,
                      double db1, double db2, double db3) {
        super(tenHP, soTinChi);
        setDb1(db1); setDb2(db2); setDb3(db3);
    }

    public void setDb1(double d) { if (d >= 0 && d <= 10) db1 = d; }
    public void setDb2(double d) { if (d >= 0 && d <= 10) db2 = d; }
    public void setDb3(double d) { if (d >= 0 && d <= 10) db3 = d; }

    @Override
    public double tinhDiem() {
        return (db1 + db2 + db3) / 3;
    }
}

6. Cách chạy

javac DiemHP.java HPLyThuyet.java HPThucHanh.java

(cần SinhVien và QuanLyHP để chạy — phần 2)

7. Kết quả chạy mẫu

(ở phần 2)

8. Bảng kiểm thử

# Ca Kỳ vọng
1 new HPLyThuyet("X",3,9,8,7).tinhDiem() 7.4
2 new HPThucHanh("Y",2,8,9,7).tinhDiem() 8.0
3 new DiemHP("Z",3) lỗi biên dịch (abstract)
4 new HPThucHanh(...,11,9,7) điểm 11 bị từ chối, tính lại theo giá trị cũ (0)

9. Trace

HPLyThuyet("Lap trinh Java", 3, 9, 8, 7): 9×0.1 = 0.9; 8×0.2 = 1.6; 7×0.7 = 4.9; tổng 7.4. toString() → "Lap trinh Java (3 TC): 7.4".

10. Lỗi thường gặp

Code sai Thông báo Sửa
new DiemHP("X", 3) DiemHP is abstract; cannot be instantiated Tạo lớp con
Lớp con không viết tinhDiem HPLyThuyet is not abstract and does not override abstract method tinhDiem() Override
public abstract double tinhDiem() { return 0; } abstract methods cannot have a body Bỏ thân
super(tenHP, tc) ở dòng 2 call to super must be first statement in constructor Dòng đầu
private field ở cha rồi truy cập chuyenCan từ con cannot find symbol Khai báo field ở đúng lớp
@Override sai chữ ký (tinhDiem(int)) method does not override or implement a method from a supertype Đúng chữ ký

11. Câu hỏi kiểm tra hiểu

  1. Vì sao DiemHP nên abstract thay vì có tinhDiem() trả 0?
  2. Vì sao toString đặt ở lớp cha vẫn in đúng điểm của từng loại?
  3. Nếu DiemHP là interface, ta mất gì? (gợi ý: thuộc tính + code dùng chung)

12. Mở rộng


PHẦN 2 — SinhVien VÀ CHƯƠNG TRÌNH CHÍNH

0. Đề bài

SinhVien: hoTen, hp1, hp2 (mỗi học phần có thể lý thuyết hoặc thực hành); constructor; tinhDTB() theo số tín chỉ: (diem1·tc1 + diem2·tc2)/(tc1 + tc2). Tạo mảng 3 sinh viên có cả lý thuyết và thực hành; in họ tên, điểm 2 học phần, DTB.

1. Yêu cầu ẩn

2. Input → Output

Vào Ra
3 SinhVien, mỗi người 2 DiemHP họ tên + điểm từng HP + DTB

3. Thiết kế

        SinhVien
  - hoTen : String
  - hp1, hp2 : DiemHP
  + SinhVien(hoTen, hp1, hp2)
  + tinhDTB() : double
  + toString() : String

Không cần biết hp1 là lý thuyết hay thực hành: chỉ gọi hp1.tinhDiem().

4. Code từng bước

Bước 1 — constructor + DTB.

public double tinhDTB() {
    int tc1 = hp1.getSoTinChi();
    int tc2 = hp2.getSoTinChi();
    if (tc1 + tc2 == 0) return 0;
    return (hp1.tinhDiem() * tc1 + hp2.tinhDiem() * tc2) / (tc1 + tc2);
}

Bước 2 — toString nhiều dòng.

@Override
public String toString() {
    double dtb = Math.round(tinhDTB() * 100) / 100.0;
    return hoTen + "\n  " + hp1 + "\n  " + hp2 + "\n  DTB = " + dtb;
}

Bước 3 — mảng 3 sinh viên (chú ý new từng ô).

5. Lời giải hoàn chỉnh

// ===== SinhVien.java =====
public class SinhVien {
    private String hoTen;
    private DiemHP hp1, hp2;

    public SinhVien(String hoTen, DiemHP hp1, DiemHP hp2) {
        this.hoTen = hoTen;
        this.hp1 = hp1;
        this.hp2 = hp2;
    }

    public String getHoTen() { return hoTen; }
    public DiemHP getHp1()   { return hp1; }
    public DiemHP getHp2()   { return hp2; }

    public double tinhDTB() {
        int tc1 = hp1.getSoTinChi();
        int tc2 = hp2.getSoTinChi();
        if (tc1 + tc2 == 0) return 0;
        return (hp1.tinhDiem() * tc1 + hp2.tinhDiem() * tc2) / (tc1 + tc2);
    }

    @Override
    public String toString() {
        double dtb = Math.round(tinhDTB() * 100) / 100.0;
        return hoTen + "\n  " + hp1 + "\n  " + hp2 + "\n  DTB = " + dtb;
    }
}
// ===== QuanLyHP.java =====
public class QuanLyHP {
    public static void main(String[] args) {
        DiemHP lt1 = new HPLyThuyet("Lap trinh Java", 3, 9, 8, 7);
        DiemHP th1 = new HPThucHanh("Thuc hanh Java", 2, 8, 9, 7);

        DiemHP th2 = new HPThucHanh("Thuc hanh Java", 2, 6, 7, 8);
        DiemHP lt2 = new HPLyThuyet("Toan roi rac", 3, 10, 9, 8);

        DiemHP lt3 = new HPLyThuyet("Co so du lieu", 4, 5, 6, 7);
        DiemHP th3 = new HPThucHanh("Thuc hanh CSDL", 1, 10, 10, 9);

        SinhVien[] ds = new SinhVien[3];
        ds[0] = new SinhVien("Nguyen Van An", lt1, th1);
        ds[1] = new SinhVien("Tran Thi Binh", th2, lt2);
        ds[2] = new SinhVien("Le Van Chi", lt3, th3);

        for (int i = 0; i < ds.length; i++) {
            System.out.println(ds[i]);
            System.out.println();
        }

        // Da hinh: cung mot loi goi, moi loai tu tinh
        DiemHP[] cacHP = {lt1, th1, th2, lt2, lt3, th3};
        double tong = 0;
        for (int i = 0; i < cacHP.length; i++) {
            tong += cacHP[i].tinhDiem();
        }
        System.out.println("Tong diem 6 hoc phan: "
                         + Math.round(tong * 100) / 100.0);
    }
}

6. Cách chạy

javac DiemHP.java HPLyThuyet.java HPThucHanh.java SinhVien.java QuanLyHP.java
java QuanLyHP

7. Kết quả chạy mẫu

Nguyen Van An
  Lap trinh Java (3 TC): 7.4
  Thuc hanh Java (2 TC): 8.0
  DTB = 7.64

Tran Thi Binh
  Thuc hanh Java (2 TC): 7.0
  Toan roi rac (3 TC): 8.4
  DTB = 7.84

Le Van Chi
  Co so du lieu (4 TC): 6.6
  Thuc hanh CSDL (1 TC): 9.67
  DTB = 7.21

Tong diem 6 hoc phan: 47.07

Kiểm tra tay:

8. Bảng kiểm thử

# Ca Kỳ vọng
1 2 môn đều lý thuyết, cùng tín chỉ DTB = trung bình cộng
2 Tín chỉ 3 và 1, điểm 9 và 5 (27+5)/4 = 8.0
3 hp1 = null NullPointerException → cần chặn ở constructor (nâng cao)
4 Tổng tín chỉ 0 (dữ liệu sai) DTB = 0, không chia 0

9. Trace tinhDTB của An

Bước tc1 tc2 hp1.tinhDiem() hp2.tinhDiem() Tử Mẫu DTB
đọc 3 2 7.4 8.0 — — —
tính 22.2 3
tính 38.2 5 7.64

10. Lỗi thường gặp

Code sai Thông báo / hiện tượng Sửa
HPLyThuyet hp1 thay vì DiemHP hp1 Không nhận được HPThucHanh Khai báo kiểu cha
SinhVien[] ds = new SinhVien[3]; ds[0].tinhDTB() NullPointerException new SinhVien(...) cho từng ô
DTB chia hp1.getSoTinChi() Sai công thức Chia tổng tín chỉ
hp1.tinhDiem thiếu () cannot find symbol / in địa chỉ phương thức Thêm ()
toString thiếu \n Cả 3 sinh viên dính một dòng Thêm \n

11. Câu hỏi kiểm tra hiểu

  1. Vì sao khai báo DiemHP hp1 thay vì HPLyThuyet hp1 lại quan trọng?
  2. Nếu thêm HPDoAn, cần sửa những tệp nào? (Đáp án: chỉ thêm tệp mới.)
  3. Vì sao SinhVien không nên có phương thức tinhDiem()? (nó không phải học phần)

12. Mở rộng


PHẦN 3 — MỞ RỘNG CỦA ĐỀ

3.1 HPDoAn — trung bình 5 thành viên hội đồng

// ===== HPDoAn.java =====
public class HPDoAn extends DiemHP {
    private double[] diemHoiDong;

    public HPDoAn(String tenHP, int soTinChi, double[] diemHoiDong) {
        super(tenHP, soTinChi);
        this.diemHoiDong = diemHoiDong;
    }

    @Override
    public double tinhDiem() {
        if (diemHoiDong == null || diemHoiDong.length == 0) return 0;
        double s = 0;
        for (int i = 0; i < diemHoiDong.length; i++) s += diemHoiDong[i];
        return s / diemHoiDong.length;
    }
}

Điểm quan trọng: SinhVien không đổi một dòng nào. Đây là bằng chứng đa hình có giá trị thật.

Kiểm thử: 5 điểm 9, 8, 8, 9, 7 → 41/5 = 8.2. Nếu SinhVien("X", new HPDoAn("Do an", 3, new double[]{9,8,8,9,7}), lt2) → DTB = (8.2×3 + 8.4×3)/6 = (24.6 + 25.2)/6 = 49.8/6 = 8.3.

3.2 Số bài thực hành thay đổi

public class HPThucHanh extends DiemHP {
    private double[] db;                      // thay 3 biến bằng mảng

    public HPThucHanh(String tenHP, int soTinChi, double[] db) {
        super(tenHP, soTinChi);
        this.db = db;
    }

    @Override
    public double tinhDiem() {
        if (db == null || db.length == 0) return 0;
        double s = 0;
        for (int i = 0; i < db.length; i++) s += db[i];
        return s / db.length;                 // chia theo so bai thuc te
    }
}

Lưu ý: đổi constructor của HPThucHanh sẽ phải sửa QuanLyHP (vì cách gọi thay đổi) — đây là khác biệt giữa "mở rộng thêm lớp" (không sửa gì) và "đổi chữ ký lớp cũ" (phải sửa nơi gọi).

3.3 Nhiều học phần

Đổi SinhVien:

private DiemHP[] dsHP;
private int soHP;

public boolean themHP(DiemHP hp) {
    if (hp == null || soHP >= dsHP.length) return false;
    dsHP[soHP++] = hp;
    return true;
}

public double tinhDTB() {
    double t = 0; int tc = 0;
    for (int i = 0; i < soHP; i++) {
        t  += dsHP[i].tinhDiem() * dsHP[i].getSoTinChi();
        tc += dsHP[i].getSoTinChi();
    }
    return (tc == 0) ? 0 : t / tc;
}

PHẦN 4 (Ở NHÀ) — HỆ THỐNG BƯU PHẨM

0. Đề bài

Thùng thư chứa 2 loại bưu phẩm: Thư (thường: dán tem 800đ; bảo đảm: 2000đ) và Bưu kiện (5000đ). Thùng thư cho phép bỏ vào, liệt kê toàn bộ hoặc theo loại, tính tổng tiền, tổng theo từng loại. Chương trình: tạo thùng chứa 100 bưu phẩm; bỏ vào đủ loại; liệt kê; liệt kê thư bảo đảm; tính tổng tiền; tính tổng theo từng loại.

1. Yêu cầu ẩn

2. Input → Output

Vào Ra
BuuPham[] (tối đa 100) danh sách + tổng tiền + tổng theo loại

3. Thiết kế

                 BuuPham «abstract»
            - ma : String
            + phiGui() : double   «abstract»
            + loai() : String     «abstract»
                ^           ^
                |           |
              Thu        BuuKien
   - baoDam : boolean     (phi 5000)
     phi 800/2000

                 ThungThu
       - ds : BuuPham[100]
       - soLuong : int
       + them(p) : boolean
       + lietKe() / lietKeTheoLoai(String)
       + tongTien() : double
       + tongTheoLoai(String) : double

Vì sao loai() là phương thức chứ không phải thuộc tính: mỗi lớp tự trả lời, ThungThu không cần biết chi tiết.

4. Code từng bước

Bước 1 — lớp trừu tượng.

public abstract class BuuPham {
    private String ma;
    public BuuPham(String ma) { this.ma = ma; }
    public String getMa() { return ma; }
    public abstract double phiGui();
    public abstract String loai();

    @Override
    public String toString() {
        return ma + " | " + loai() + " | " + phiGui();
    }
}

Bước 2 — Thu với hai mức phí.

public double phiGui() { return baoDam ? 2000 : 800; }
public String loai()   { return baoDam ? "Thu bao dam" : "Thu thuong"; }

Bước 3 — BuuKien.

public double phiGui() { return 5000; }
public String loai()   { return "Buu kien"; }

Bước 4 — ThungThu: thêm, liệt kê, tổng.

public double tongTien() {
    double t = 0;
    for (int i = 0; i < soLuong; i++) t += ds[i].phiGui();
    return t;
}

public double tongTheoLoai(String loai) {
    double t = 0;
    for (int i = 0; i < soLuong; i++)
        if (ds[i].loai().equals(loai)) t += ds[i].phiGui();
    return t;
}

5. Lời giải hoàn chỉnh

// ===== BuuPham.java =====
public abstract class BuuPham {
    private String ma;

    public BuuPham(String ma) { this.ma = ma; }

    public String getMa() { return ma; }

    public abstract double phiGui();
    public abstract String loai();

    @Override
    public String toString() {
        return ma + " | " + loai() + " | " + phiGui();
    }
}
// ===== Thu.java =====
public class Thu extends BuuPham {
    private boolean baoDam;

    public Thu(String ma, boolean baoDam) {
        super(ma);
        this.baoDam = baoDam;
    }

    @Override
    public double phiGui() { return baoDam ? 2000 : 800; }

    @Override
    public String loai() { return baoDam ? "Thu bao dam" : "Thu thuong"; }
}
// ===== BuuKien.java =====
public class BuuKien extends BuuPham {
    public BuuKien(String ma) { super(ma); }

    @Override
    public double phiGui() { return 5000; }

    @Override
    public String loai() { return "Buu kien"; }
}
// ===== ThungThu.java =====
public class ThungThu {
    private BuuPham[] ds;
    private int soLuong;

    public ThungThu(int sucChua) {
        ds = new BuuPham[sucChua];
        soLuong = 0;
    }

    public boolean them(BuuPham p) {
        if (p == null || soLuong >= ds.length) return false;
        ds[soLuong] = p;
        soLuong++;
        return true;
    }

    public void lietKe() {
        for (int i = 0; i < soLuong; i++) System.out.println(ds[i]);
    }

    public void lietKeTheoLoai(String loai) {
        for (int i = 0; i < soLuong; i++) {
            if (ds[i].loai().equals(loai)) System.out.println(ds[i]);
        }
    }

    public double tongTien() {
        double t = 0;
        for (int i = 0; i < soLuong; i++) t += ds[i].phiGui();
        return t;
    }

    public double tongTheoLoai(String loai) {
        double t = 0;
        for (int i = 0; i < soLuong; i++) {
            if (ds[i].loai().equals(loai)) t += ds[i].phiGui();
        }
        return t;
    }

    public int getSoLuong() { return soLuong; }
}
// ===== QuanLyBuuPham.java =====
public class QuanLyBuuPham {
    public static void main(String[] args) {
        ThungThu thung = new ThungThu(100);

        thung.them(new Thu("T1", false));
        thung.them(new Thu("T2", false));
        thung.them(new Thu("T3", false));
        thung.them(new Thu("T4", true));
        thung.them(new Thu("T5", true));
        thung.them(new BuuKien("B1"));
        thung.them(new BuuKien("B2"));
        thung.them(new BuuKien("B3"));

        System.out.println("--- Tat ca buu pham ---");
        thung.lietKe();

        System.out.println("--- Thu bao dam ---");
        thung.lietKeTheoLoai("Thu bao dam");

        System.out.println("Tong tien: " + thung.tongTien());
        System.out.println("Thu thuong : " + thung.tongTheoLoai("Thu thuong"));
        System.out.println("Thu bao dam: " + thung.tongTheoLoai("Thu bao dam"));
        System.out.println("Buu kien   : " + thung.tongTheoLoai("Buu kien"));
        System.out.println("So luong   : " + thung.getSoLuong());
    }
}

6. Cách chạy

javac BuuPham.java Thu.java BuuKien.java ThungThu.java QuanLyBuuPham.java
java QuanLyBuuPham

7. Kết quả chạy mẫu

--- Tat ca buu pham ---
T1 | Thu thuong | 800.0
T2 | Thu thuong | 800.0
T3 | Thu thuong | 800.0
T4 | Thu bao dam | 2000.0
T5 | Thu bao dam | 2000.0
B1 | Buu kien | 5000.0
B2 | Buu kien | 5000.0
B3 | Buu kien | 5000.0
--- Thu bao dam ---
T4 | Thu bao dam | 2000.0
T5 | Thu bao dam | 2000.0
Tong tien: 21400.0
Thu thuong : 2400.0
Thu bao dam: 4000.0
Buu kien   : 15000.0
So luong   : 8

Kiểm tra tay: 3×800 = 2400; 2×2000 = 4000; 3×5000 = 15000; tổng 21400 ✓; 2400 + 4000 + 15000 = 21400 ✓.

8. Bảng kiểm thử

# Ca Kỳ vọng
1 8 bưu phẩm như trên 21400
2 Thùng rỗng tổng 0, liệt kê không in gì
3 Thêm quá 100 false
4 Liệt kê "Thu thuong" 3 dòng
5 Thêm null false

9. Trace tongTheoLoai("Thu bao dam")

i ds[i].loai() So khớp? t
0 Thu thuong không 0
1 Thu thuong không 0
2 Thu thuong không 0
3 Thu bao dam có 2000
4 Thu bao dam có 4000
5–7 Buu kien không 4000

10. Lỗi thường gặp

Code sai Thông báo / hiện tượng Sửa
ThungThu tự if (p instanceof Thu) để tính tiền Chạy được nhưng phá đa hình Gọi p.phiGui()
BuuPham không abstract new BuuPham() tạo object vô nghĩa Thêm abstract
Lớp con thiếu loai() Thu is not abstract and does not override abstract method loai() Override
ds[soLuong++] = p không kiểm tra đầy ArrayIndexOutOfBoundsException Kiểm tra trước
So sánh ds[i].loai() == loai Không khớp .equals(loai)
phiGui trả int cannot override ... return type int is not compatible with double Trả double

11. Câu hỏi kiểm tra hiểu

  1. Vì sao ThungThu không cần biết "thư bảo đảm giá 2000"?
  2. Nếu thêm loại "Chuyển phát nhanh 12000đ", cần sửa những tệp nào?
  3. Vì sao loai() không nên là thuộc tính String loai gán trong constructor?

12. Mở rộng


Checklist nộp Lab 05

🎧
Lồng tiếng tóm tắt bài giảng (ZeroTTS AI)
Đang đọc: Mai Chi (Nữ) · Thời lượng ~1–2 phút
ZeroTTS AI
00:00
--:--
📝 Lời thuyết minh (Tự động tô sáng câu đang đọc • Bấm vào câu để tua tới):
Đang nạp dữ liệu lời đọc...