Lab 04 — SV, DSSV, java.util.Date

LAB 04 — GIẢI CHI TIẾT (LỚP SV, DANH SÁCH DSSV, java.util.Date)

Nguồn: lab04.doc (Bài thực hành số 04). Bám lý thuyết buổi 2, 4, 10. Đây là lab "tổng hợp": lớp có ngày sinh, chuỗi, mảng, sắp xếp, tìm kiếm, xóa.

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

Phần Lớp Tệp Kỹ thuật mới
Chính SV SV.java java.util.Date, tách họ/tên, tuổi, xếp loại
Chính DSSV DSSV.java mảng đối tượng, sắp xếp 3 tiêu chí, xóa dồn mảng
Chạy — QuanLyDSSV.java 5 sinh viên, 6 thao tác theo đề
Ở nhà SV mở rộng (thêm vào SV.java) lonHon, gioiHon, giongNhau, chuanHoTen
Ở nhà DSSV mở rộng (thêm vào DSSV.java) chuanHoTen, trungSV

PHẦN 1 — LỚP SV

0. Đề bài

SV gồm: hoTen, ngaySinh (Date), dtb. Phương thức: SV(String, Date, double), layHoTen, ganHoTen, layNgaySinh, ganNgaySinh, layDTB, ganDTB, hienThi, layHo, layTen, layDem, layTuoi, layXepLoai.

1. Yêu cầu ẩn

2. Input → Output

Phương thức Vào Ra Ví dụ
layHo() — String "Nguyen Van An" → "Nguyen"
layTen() — String → "An"
layDem() — String → "Van"
layTuoi() — int sinh 2005 → 21
layXepLoai() — String 7.2 → "Kha"

3. Thiết kế

        SV
  - hoTen : String
  - ngaySinh : Date
  - dtb : double
  + SV(String, Date, double)
  + layHoTen/ganHoTen   layNgaySinh/ganNgaySinh   layDTB/ganDTB
  + hienThi()
  + layHo() : String   + layDem() : String   + layTen() : String
  + layTuoi() : int    + layXepLoai() : String

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

  1. Không lưu ho, dem, ten thành 3 thuộc tính — nếu lưu, khi ganHoTen phải cập nhật 3 chỗ, dễ lệch dữ liệu. Thay vào đó tính khi cần (derived data).
  2. dtb để private, setter kiểm tra 0..10.
  3. layTuoi() dùng năm cố định 2026 (theo năm hiện tại) — ghi rõ giả định.

4. Code từng bước

Bước 1 — thuộc tính, constructor, getter/setter.

public class SV {
    private String hoTen;
    private Date ngaySinh;
    private double dtb;

    public SV(String hoTen, Date ngaySinh, double dtb) {
        ganHoTen(hoTen);
        this.ngaySinh = ngaySinh;
        ganDTB(dtb);
    }

    public void ganDTB(double d) { if (d >= 0 && d <= 10) dtb = d; }

Bước 2 — tách họ/tên bằng split.

private String[] tu() {
    return hoTen.trim().split("\\s+");   // "\s+" = 1 hoac nhieu dau cach
}

public String layHo()  { return tu()[0]; }
public String layTen() { String[] p = tu(); return p[p.length - 1]; }
public String layDem() {
    String[] p = tu();
    String dem = "";
    for (int i = 1; i < p.length - 1; i++) {
        dem += p[i];
        if (i < p.length - 2) dem += " ";
    }
    return dem;                          // 1 tu -> ""
}

Bước 3 — tuổi (getYear() + 1900).

public int layTuoi() { return 2026 - (ngaySinh.getYear() + 1900); }

Bước 4 — xếp loại + hiển thị.

public String layXepLoai() {
    if (dtb >= 8) return "Gioi";
    if (dtb >= 7) return "Kha";
    if (dtb >= 5) return "Trung binh";
    return "Yeu";
}

public void hienThi() {
    System.out.println(hoTen + " | " + ngaySinhS() + " | DTB " + dtb
                     + " | " + layXepLoai() + " | " + layTuoi() + " tuoi");
}

ngaySinhS() là phương thức phụ in ngày dạng dd/M/yyyy (vì Date.toString() rất xấu):

public String ngaySinhS() {
    return ngaySinh.getDate() + "/" + (ngaySinh.getMonth() + 1) + "/"
         + (ngaySinh.getYear() + 1900);
}

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

// ===== SV.java =====
import java.util.Date;

public class SV {
    private String hoTen;
    private Date ngaySinh;
    private double dtb;

    public SV(String hoTen, Date ngaySinh, double dtb) {
        ganHoTen(hoTen);
        this.ngaySinh = ngaySinh;
        ganDTB(dtb);
    }

    public String layHoTen() { return hoTen; }
    public void ganHoTen(String hoTen) {
        this.hoTen = (hoTen == null) ? "" : hoTen.trim();
    }

    public Date layNgaySinh() { return ngaySinh; }
    public void ganNgaySinh(Date ngaySinh) { this.ngaySinh = ngaySinh; }

    public double layDTB() { return dtb; }
    public void ganDTB(double d) { if (d >= 0 && d <= 10) dtb = d; }

    private String[] tu() {
        String s = (hoTen == null) ? "" : hoTen.trim();
        if (s.length() == 0) return new String[]{""};
        return s.split("\\s+");
    }

    public String layHo()  { return tu()[0]; }

    public String layTen() {
        String[] p = tu();
        return p[p.length - 1];
    }

    public String layDem() {
        String[] p = tu();
        String dem = "";
        for (int i = 1; i < p.length - 1; i++) {
            dem += p[i];
            if (i < p.length - 2) dem += " ";
        }
        return dem;
    }

    public int layTuoi() {
        return 2026 - (ngaySinh.getYear() + 1900);
    }

    public String layXepLoai() {
        if (dtb >= 8) return "Gioi";
        if (dtb >= 7) return "Kha";
        if (dtb >= 5) return "Trung binh";
        return "Yeu";
    }

    public String ngaySinhS() {
        return ngaySinh.getDate() + "/" + (ngaySinh.getMonth() + 1) + "/"
             + (ngaySinh.getYear() + 1900);
    }

    // ---- cac phuong thuc cua phan "o nha" ----
    public boolean lonHon(SV sv) {
        return this.layTuoi() > sv.layTuoi();
    }

    public boolean gioiHon(SV sv) {
        return this.layDTB() > sv.layDTB();
    }

    public boolean giongNhau(SV sv) {
        if (sv == null) return false;
        return this.hoTen.equalsIgnoreCase(sv.hoTen)
            && this.ngaySinh.equals(sv.ngaySinh);
    }

    public void chuanHoTen() {
        String[] p = tu();
        String kq = "";
        for (int i = 0; i < p.length; i++) {
            String tu = p[i].toLowerCase();
            if (tu.length() > 0) {
                tu = tu.substring(0, 1).toUpperCase() + tu.substring(1);
            }
            kq += tu;
            if (i < p.length - 1) kq += " ";
        }
        hoTen = kq;
    }

    public void hienThi() {
        System.out.println(hoTen + " | " + ngaySinhS() + " | DTB " + dtb
                         + " | " + layXepLoai() + " | " + layTuoi() + " tuoi");
    }

    @Override
    public String toString() { return hoTen; }
}

6. Cách chạy

javac SV.java

(chưa chạy được một mình — cần DSSV ở phần 2)

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

Nguyen Van An | 15/3/2005 | DTB 8.5 | Gioi | 21 tuoi

8. Bảng kiểm thử

# hoTen layHo layDem layTen
1 "Nguyen Van An" Nguyen Van An
2 "An" An "" An
3 "Nguyen Thi Hoang Yen" Nguyen Thi Hoang Yen
4 " Tran Van Binh " Tran Van Binh

9. Trace

hoTen = " Nguyen Van An ": trim() → "Nguyen Van An"; split("\\s+") → ["Nguyen","Van","An"]; layHo = p[0] = "Nguyen"; layTen = p[2] = "An"; layDem: i chạy 1..1 → "Van".

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

Code sai Thông báo / hiện tượng Sửa
hoTen.split(" ") với nhiều dấu cách Phần tử rỗng trong mảng split("\\s+")
hoTen.split(" ")[hoTen.length()] ArrayIndexOutOfBoundsException Dùng p.length - 1
2026 - ngaySinh.getYear() Tuổi sai 1900 + 1900
ngaySinh.getMonth() in ra tháng 2 cho tháng 3 Lệch 1 + 1
dtb public Gán được 15 private + setter
if (dtb >= 8) ... else if (dtb >= 7) ngược thứ tự Phân loại sai Từ cao xuống thấp

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

  1. Vì sao không lưu ho, dem, ten thành thuộc tính?
  2. layDem() trả gì với tên 1 từ? 2 từ?
  3. Vì sao 2026 nên là hằng số (static final int NAM_HIEN_TAI = 2026)?

12. Mở rộng


PHẦN 2 — LỚP DSSV

0. Đề bài

DSSV: SV[] ds, int soSV. DSSV(int), them(SV), laySV(int), hienThi(), sapHoten(), sapTuoi(), sapDTB(), timTen(String), lietKeXepLoai(String), xoa(String).

1. Yêu cầu ẩn

2. Input → Output

Phương thức Vào Ra
them(SV) SV boolean
laySV(int) chỉ số SV hoặc null
timTen(String) tên SV hoặc null
xoa(String) tên boolean

3. Thiết kế

          DSSV
  - ds : SV[]
  - soSV : int
  + DSSV(int)
  + them(SV) : boolean
  + laySV(int) : SV
  + hienThi() : void
  + sapHoten() / sapTuoi() / sapDTB() : void
  + timTen(String) : SV
  + lietKeXepLoai(String) : void
  + xoa(String) : boolean

Quyết định: soSV tách khỏi ds.length vì mảng có thể còn chỗ trống — nếu dùng ds.length thì sẽ in cả null.

4. Code từng bước

Bước 1 — thêm và truy xuất an toàn.

public boolean them(SV sv) {
    if (sv == null || soSV >= ds.length) return false;
    ds[soSV] = sv;
    soSV++;
    return true;
}

public SV laySV(int i) {
    if (i < 0 || i >= soSV) return null;
    return ds[i];
}

Bước 2 — khoá sắp xếp kiểu Việt + bubble sort dùng lại.

private String khoaTen(SV sv) {
    return sv.layTen() + " " + sv.layHo() + " " + sv.layDem();
}

public void sapHoten() {
    for (int i = 0; i < soSV - 1; i++) {
        for (int j = 0; j < soSV - 1 - i; j++) {
            if (khoaTen(ds[j]).compareTo(khoaTen(ds[j + 1])) > 0) {
                SV tmp = ds[j]; ds[j] = ds[j + 1]; ds[j + 1] = tmp;
            }
        }
    }
}

Bước 3 — sắp theo tuổi (tăng) và DTB (giảm).

public void sapTuoi() {
    for (int i = 0; i < soSV - 1; i++)
        for (int j = 0; j < soSV - 1 - i; j++)
            if (ds[j].layTuoi() > ds[j + 1].layTuoi()) { /* doi cho */ }
}

public void sapDTB() {
    for (int i = 0; i < soSV - 1; i++)
        for (int j = 0; j < soSV - 1 - i; j++)
            if (ds[j].layDTB() < ds[j + 1].layDTB()) { /* doi cho */ }
}

Bước 4 — tìm, liệt kê, xóa.

public SV timTen(String ten) {
    for (int i = 0; i < soSV; i++)
        if (ds[i].layTen().equalsIgnoreCase(ten)) return ds[i];
    return null;
}

public boolean xoa(String ten) {
    for (int k = 0; k < soSV; k++) {
        if (ds[k].layTen().equalsIgnoreCase(ten)) {
            for (int i = k; i < soSV - 1; i++) ds[i] = ds[i + 1];
            ds[soSV - 1] = null;      // bo tham chieu cu
            soSV--;
            return true;
        }
    }
    return false;
}

Bước 5 — hai phương thức phục vụ đề bài chính (đặt trong DSSV):

public double tuoiTrungBinh() {
    if (soSV == 0) return 0;
    int tong = 0;
    for (int i = 0; i < soSV; i++) tong += ds[i].layTuoi();
    return (double) tong / soSV;
}

public void tangDTBTruoc1980(double them) {
    for (int i = 0; i < soSV; i++) {
        int nam = ds[i].layNgaySinh().getYear() + 1900;
        if (nam < 1980) ds[i].ganDTB(ds[i].layDTB() + them);
    }
}

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

// ===== DSSV.java =====
public class DSSV {
    private SV[] ds;
    private int soSV;

    public DSSV(int sucChua) {
        ds = new SV[sucChua];
        soSV = 0;
    }

    public int getSoSV() { return soSV; }

    public boolean them(SV sv) {
        if (sv == null || soSV >= ds.length) return false;
        ds[soSV] = sv;
        soSV++;
        return true;
    }

    public SV laySV(int i) {
        if (i < 0 || i >= soSV) return null;
        return ds[i];
    }

    public void hienThi() {
        for (int i = 0; i < soSV; i++) {
            System.out.print((i + 1) + ". ");
            ds[i].hienThi();
        }
    }

    private String khoaTen(SV sv) {
        return sv.layTen() + " " + sv.layHo() + " " + sv.layDem();
    }

    public void sapHoten() {
        for (int i = 0; i < soSV - 1; i++) {
            for (int j = 0; j < soSV - 1 - i; j++) {
                if (khoaTen(ds[j]).compareTo(khoaTen(ds[j + 1])) > 0) {
                    SV tmp = ds[j];
                    ds[j] = ds[j + 1];
                    ds[j + 1] = tmp;
                }
            }
        }
    }

    public void sapTuoi() {
        for (int i = 0; i < soSV - 1; i++) {
            for (int j = 0; j < soSV - 1 - i; j++) {
                if (ds[j].layTuoi() > ds[j + 1].layTuoi()) {
                    SV tmp = ds[j];
                    ds[j] = ds[j + 1];
                    ds[j + 1] = tmp;
                }
            }
        }
    }

    public void sapDTB() {
        for (int i = 0; i < soSV - 1; i++) {
            for (int j = 0; j < soSV - 1 - i; j++) {
                if (ds[j].layDTB() < ds[j + 1].layDTB()) {
                    SV tmp = ds[j];
                    ds[j] = ds[j + 1];
                    ds[j + 1] = tmp;
                }
            }
        }
    }

    public SV timTen(String ten) {
        for (int i = 0; i < soSV; i++) {
            if (ds[i].layTen().equalsIgnoreCase(ten)) return ds[i];
        }
        return null;
    }

    public void lietKeXepLoai(String loai) {
        for (int i = 0; i < soSV; i++) {
            if (ds[i].layXepLoai().equalsIgnoreCase(loai)) ds[i].hienThi();
        }
    }

    public boolean xoa(String ten) {
        for (int k = 0; k < soSV; k++) {
            if (ds[k].layTen().equalsIgnoreCase(ten)) {
                for (int i = k; i < soSV - 1; i++) ds[i] = ds[i + 1];
                ds[soSV - 1] = null;
                soSV--;
                return true;
            }
        }
        return false;
    }

    public double tuoiTrungBinh() {
        if (soSV == 0) return 0;
        int tong = 0;
        for (int i = 0; i < soSV; i++) tong += ds[i].layTuoi();
        return (double) tong / soSV;
    }

    public void tangDTBTruoc1980(double them) {
        for (int i = 0; i < soSV; i++) {
            int nam = ds[i].layNgaySinh().getYear() + 1900;
            if (nam < 1980) ds[i].ganDTB(ds[i].layDTB() + them);
        }
    }

    // ---- cac phuong thuc cua phan "o nha" ----
    public void chuanHoTen() {
        for (int i = 0; i < soSV; i++) ds[i].chuanHoTen();
    }

    public void trungSV() {
        boolean co = false;
        for (int i = 0; i < soSV - 1; i++) {
            for (int j = i + 1; j < soSV; j++) {
                if (ds[i].giongNhau(ds[j])) {
                    System.out.println("Trung: " + ds[i].layHoTen()
                                     + " va " + ds[j].layHoTen());
                    co = true;
                }
            }
        }
        if (!co) System.out.println("Khong co sinh vien trung");
    }
}

6. Cách chạy

javac SV.java DSSV.java QuanLyDSSV.java
java QuanLyDSSV

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

(xem phần 3 — chương trình QuanLyDSSV)

8. Bảng kiểm thử

# Ca Kỳ vọng
1 Thêm 6 SV vào mảng 5 chỗ SV thứ 6 trả false
2 laySV(5) khi có 5 SV null
3 xoa("KhongCo") false, danh sách không đổi
4 xoa("Hoa") xóa đúng 1 người, soSV giảm 1
5 tuoiTrungBinh() khi rỗng 0

9. Trace xoa("Hoa") với 5 SV

Bước ds[0] ds[1] ds[2] ds[3] ds[4] soSV
trước An Binh Hoa Hung Nam 5
tìm được k = 2 5
i=2: ds[2]=ds[3] An Binh Hung Hung Nam 5
i=3: ds[3]=ds[4] An Binh Hung Nam Nam 5
dọn ô cuối An Binh Hung Nam null 4

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

Code sai Thông báo / hiện tượng Sửa
for (i = k; i < soSV; i++) ds[i] = ds[i+1] ArrayIndexOutOfBoundsException khi i = soSV-1 i < soSV - 1
Không ds[soSV-1] = null Giữ tham chiếu cũ (rò rỉ, in thừa) Dọn ô cuối
sapHoten so sánh cả hoTen Sai thứ tự kiểu Việt Dùng khoaTen
khoaTen dùng ho + ten Sắp theo họ, không theo tên ten + ho + dem
if (ds[j] > ds[j+1]) bad operand types So layDTB()
them không kiểm tra đầy Ghi tràn mảng Kiểm tra soSV >= ds.length

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

  1. Vì sao cần cả soSV lẫn ds.length?
  2. Vì sao khi xóa phải dồn từ trái sang phải (không phải ngược lại)?
  3. So sánh equals và equalsIgnoreCase — dùng cái nào khi tìm tên?

12. Mở rộng


PHẦN 3 — CHƯƠNG TRÌNH QuanLyDSSV

0. Đề bài

Tạo danh sách 5 sinh viên; sắp theo họ tên; liệt kê sinh viên Giỏi; tìm sinh viên tên "Nam"; xóa sinh viên đầu tiên tên "Hòa"; tính tuổi trung bình; tăng DTB 0.5 cho SV sinh trước 1980.

1. Yêu cầu ẩn

3. Thiết kế luồng chạy

tạo 5 SV → in danh sách → sắp họ tên → in
→ liệt kê Giỏi → tìm "Nam" → xóa "Hoa"
→ in danh sách còn lại → tuổi TB → tăng DTB → in

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

// ===== QuanLyDSSV.java =====
import java.util.Date;

public class QuanLyDSSV {
    public static void main(String[] args) {
        DSSV dssv = new DSSV(10);

        dssv.them(new SV("Nguyen Van An",   new Date("03/15/2005"), 8.5));
        dssv.them(new SV("Tran Thi Binh",   new Date("07/22/2004"), 7.2));
        dssv.them(new SV("Le Hoang Nam",    new Date("11/02/2005"), 6.8));
        dssv.them(new SV("Pham Thi Hoa",    new Date("05/10/2003"), 9.1));
        dssv.them(new SV("Do Van Hung",     new Date("01/30/1978"), 4.5));

        System.out.println("--- Danh sach ban dau ---");
        dssv.hienThi();

        System.out.println("--- Sap xep theo ho ten ---");
        dssv.sapHoten();
        dssv.hienThi();

        System.out.println("--- Sinh vien Gioi ---");
        dssv.lietKeXepLoai("Gioi");

        System.out.println("--- Tim sinh vien ten Nam ---");
        SV tim = dssv.timTen("Nam");
        if (tim != null) tim.hienThi();
        else System.out.println("Khong tim thay");

        System.out.println("--- Xoa sinh vien dau tien ten Hoa ---");
        System.out.println("Ket qua xoa: " + dssv.xoa("Hoa"));
        dssv.hienThi();

        System.out.println("Tuoi trung binh: " + dssv.tuoiTrungBinh());

        System.out.println("--- Tang 0.5 DTB cho SV sinh truoc 1980 ---");
        dssv.tangDTBTruoc1980(0.5);
        dssv.hienThi();
    }
}

6. Cách chạy

javac SV.java DSSV.java QuanLyDSSV.java
java QuanLyDSSV

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

--- Danh sach ban dau ---
1. Nguyen Van An | 15/3/2005 | DTB 8.5 | Gioi | 21 tuoi
2. Tran Thi Binh | 22/7/2004 | DTB 7.2 | Kha | 22 tuoi
3. Le Hoang Nam | 2/11/2005 | DTB 6.8 | Trung binh | 21 tuoi
4. Pham Thi Hoa | 10/5/2003 | DTB 9.1 | Gioi | 23 tuoi
5. Do Van Hung | 30/1/1978 | DTB 4.5 | Yeu | 48 tuoi
--- Sap xep theo ho ten ---
1. Nguyen Van An | 15/3/2005 | DTB 8.5 | Gioi | 21 tuoi
2. Tran Thi Binh | 22/7/2004 | DTB 7.2 | Kha | 22 tuoi
3. Pham Thi Hoa | 10/5/2003 | DTB 9.1 | Gioi | 23 tuoi
4. Do Van Hung | 30/1/1978 | DTB 4.5 | Yeu | 48 tuoi
5. Le Hoang Nam | 2/11/2005 | DTB 6.8 | Trung binh | 21 tuoi
--- Sinh vien Gioi ---
Nguyen Van An | 15/3/2005 | DTB 8.5 | Gioi | 21 tuoi
Pham Thi Hoa | 10/5/2003 | DTB 9.1 | Gioi | 23 tuoi
--- Tim sinh vien ten Nam ---
Le Hoang Nam | 2/11/2005 | DTB 6.8 | Trung binh | 21 tuoi
--- Xoa sinh vien dau tien ten Hoa ---
Ket qua xoa: true
1. Nguyen Van An | 15/3/2005 | DTB 8.5 | Gioi | 21 tuoi
2. Tran Thi Binh | 22/7/2004 | DTB 7.2 | Kha | 22 tuoi
3. Do Van Hung | 30/1/1978 | DTB 4.5 | Yeu | 48 tuoi
4. Le Hoang Nam | 2/11/2005 | DTB 6.8 | Trung binh | 21 tuoi
Tuoi trung binh: 28.0
--- Tang 0.5 DTB cho SV sinh truoc 1980 ---
1. Nguyen Van An | 15/3/2005 | DTB 8.5 | Gioi | 21 tuoi
2. Tran Thi Binh | 22/7/2004 | DTB 7.2 | Kha | 22 tuoi
3. Do Van Hung | 30/1/1978 | DTB 5.0 | Trung binh | 48 tuoi
4. Le Hoang Nam | 2/11/2005 | DTB 6.8 | Trung binh | 21 tuoi

Kiểm tra tay:

8. Bảng kiểm thử

# Thao tác Kỳ vọng
1 In ban đầu đúng 5 dòng, đúng thứ tự nhập
2 sapHoten An, Binh, Hoa, Hung, Nam
3 lietKeXepLoai("Gioi") 2 dòng (An, Hoa)
4 timTen("Nam") Le Hoang Nam
5 xoa("Hoa") còn 4 SV, không có Hoa
6 tuoiTrungBinh 28.0
7 tangDTBTruoc1980(0.5) Hung 5.0

9. Trace tangDTBTruoc1980

SV năm sinh < 1980? DTB trước DTB sau
An 2005 không 8.5 8.5
Binh 2004 không 7.2 7.2
Hung 1978 có 4.5 5.0
Nam 2005 không 6.8 6.8

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

Code sai Hiện tượng Sửa
Xóa rồi vẫn in soSV cũ In dòng null In theo soSV hiện tại
new Date(2005, 3, 15) Năm 3905, tháng lệch new Date("03/15/2005")
timTen in luôn trong lớp DSSV Không tái sử dụng được Trả SV, main quyết định in
Tăng DTB không kiểm tra trần 10 DTB > 10 Math.min(10, dtb + them)
So sánh tên bằng == Không khớp equals/equalsIgnoreCase

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

  1. Vì sao Ket qua xoa: true là cần thiết (nếu không in, làm sao biết xóa thành công)?
  2. Nếu đổi thứ tự "xóa Hoa" lên trước "tính tuổi TB" thì kết quả đổi thế nào?
  3. Vì sao Hung được nâng lên đúng 5.0 mà không vượt 10?

12. Mở rộng


PHẦN 4 (Ở NHÀ) — CÁC PHƯƠNG THỨC BỔ SUNG

4.1 SV.lonHon(SV), gioiHon(SV), giongNhau(SV)

Phân tích: ba phương thức so sánh hai sinh viên, nên phải nhận SV làm tham số và trả boolean.

// them vao SV.java
public boolean lonHon(SV sv) {
    return this.layTuoi() > sv.layTuoi();
}

public boolean gioiHon(SV sv) {
    return this.layDTB() > sv.layDTB();
}

public boolean giongNhau(SV sv) {
    if (sv == null) return false;
    return this.hoTen.equalsIgnoreCase(sv.hoTen)
        && this.ngaySinh.equals(sv.ngaySinh);
}

Lưu ý: giongNhau so cả hoTen và ngaySinh — hai người trùng tên nhưng khác ngày sinh thì không trùng. Nếu chỉ so tên, bạn sẽ gộp nhầm người khác nhau.

4.2 SV.chuanHoTen()

Chuẩn hoá: bỏ khoảng trắng thừa, viết hoa chữ đầu mỗi từ, còn lại viết thường.

// them vao SV.java
public void chuanHoTen() {
    String[] p = tu();
    String kq = "";
    for (int i = 0; i < p.length; i++) {
        String tu = p[i].toLowerCase();
        if (tu.length() > 0) {
            tu = tu.substring(0, 1).toUpperCase() + tu.substring(1);
        }
        kq += tu;
        if (i < p.length - 1) kq += " ";
    }
    hoTen = kq;
}

Trace " nGUYEN vAN aN ": | Bước | Kết quả | |---|---| | tu() | ["nGUYEN","vAN","aN"] | | từ 1 | "nGUYEN" → "nguyen" → "Nguyen" | | từ 2 | "vAN" → "van" → "Van" | | từ 3 | "aN" → "an" → "An" | | ghép | "Nguyen Van An" |

4.3 DSSV.chuanHoTen()

// them vao DSSV.java
public void chuanHoTen() {
    for (int i = 0; i < soSV; i++) ds[i].chuanHoTen();
}

4.4 DSSV.trungSV() — liệt kê sinh viên trùng nhau

Phân tích: so từng cặp (i, j) với j > i; nếu giongNhau thì in. Dùng j > i để mỗi cặp chỉ xét một lần.

// them vao DSSV.java
public void trungSV() {
    boolean co = false;
    for (int i = 0; i < soSV - 1; i++) {
        for (int j = i + 1; j < soSV; j++) {
            if (ds[i].giongNhau(ds[j])) {
                System.out.println("Trung: " + ds[i].layHoTen()
                                 + " va " + ds[j].layHoTen());
                co = true;
            }
        }
    }
    if (!co) System.out.println("Khong co sinh vien trung");
}

Trace 4 SV: An(2005), Binh(2004), An(2005), Nam(2005):

i j So sánh Kết quả
0 1 An vs Binh khác
0 2 An vs An (cùng ngày) trùng → in
0 3 An vs Nam khác
1 2 Binh vs An khác
1 3 Binh vs Nam khác
2 3 An vs Nam khác

4.5 Checklist nộp Lab 04

🎧
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...