Đặc điểm cốt lõi của OOP
Đóng gói (Encapsulation)
Ẩn giấu chi tiết bên trong, chỉ tiết lộ giao diện cần thiết. Giúp bảo vệ dữ liệu và tăng khả năng tái sử dụng.
Kế thừa (Inheritance)
Cho phép lớp con thừa hưởng thuộc tính và phương thức từ lớp cha. Lớp con có thể ghi đè phương thức khi cần mở rộng hành vi.
Đa hình (Polymorphism)
Cùng một thao tác nhưng cho kết quả khác nhau tùy theo đối tượng thực thi. Thường đạt được qua kế thừa, ghi đè và ép kiểu lên.
Ví dụ minh họa
public class NhanVien {
private String hoTen;
private int namSinh;
NhanVien() {}
NhanVien(String hoTen, int namSinh) {
this.hoTen = hoTen;
this.namSinh = namSinh;
}
public String gioiThieu() {
return String.format("Tôi là %s, sinh năm %d", hoTen, namSinh);
}
}
public class KySu extends NhanVien {
KySu(String hoTen, int namSinh) {
super(hoTen, namSinh);
}
@Override
public String gioiThieu() {
return "Nghề nghiệp: Kỹ sư. " + super.gioiThieu();
}
public String lapTrinh() {
return "Đang viết code...";
}
}
public class BacSi extends NhanVien {
BacSi(String hoTen, int namSinh) {
super(hoTen, namSinh);
}
@Override
public String gioiThieu() {
return "Nghề nghiệp: Bác sĩ. " + super.gioiThieu();
}
public String khamBenh() {
return "Đang khám bệnh cho bệnh nhân...";
}
}
Thực thi đa hình
NhanVien nv1 = new KySu("Minh Anh", 1995);
NhanVien nv2 = new BacSi("Thanh Hà", 1988);
System.out.println(nv1.gioiThieu()); // Nghề nghiệp: Kỹ sư...
System.out.println(nv2.gioiThieu()); // Nghề nghiệp: Bác sĩ...
Ép kiểu trong phân cấp kế thừa
public class CoSo {
public void thaoTacChung() {
System.out.println("[CoSo] Phương thức chung - liên kết tĩnh");
}
public void thaoTacDeGhiDe() {
System.out.println("[CoSo] Chưa ghi đè");
}
}
public class DanXuat extends CoSo {
public void thaoTacRieng() {
System.out.println("[DanXuat] Phương thức độc quyền");
}
@Override
public void thaoTacDeGhiDe() {
System.out.println("[DanXuat] Đã ghi đè - liên kết động");
}
}
Ép kiểu lên (Upcasting)
Tham chiếu lớp cha trỏ đến đối tượng lớp con. Phương thức ghi đè sẽ được gọi theo kiểu động.
CoSo doiTuong = new DanXuat();
doiTuong.thaoTacChung(); // [CoSo] Phương thức chung...
doiTuong.thaoTacDeGhiDe(); // [DanXuat] Đã ghi đè...
Ép kiểu xuống (Downcasting)
Chuyển tham chiếu lớp cha về lớp con để truy cập phương thức đặc thù. Cần đảm bảo đối tượng thực sự thuộc lớp con để tránh ClassCastException.
if (doiTuong instanceof DanXuat) {
DanXuat chuyenDoi = (DanXuat) doiTuong;
chuyenDoi.thaoTacRieng(); // [DanXuat] Phương thức độc quyền
}
Lớp trừu tượng và Giao diện
| Đặc điểm | Lớp trừu tượng (abstract) | Giao diện (interface) |
|---|---|---|
| Số lượng kế thừa | Đơn kế thừa | Đa kế thừa |
| Khởi tạo | Không thể trực tiếp | Không thể trực tiếp |
| Phương thức | Có thể có phương thức thường | Java 8+: có default và static |
| Mục đích | Cơ sở triển khai chung | Định nghĩa hợp đồng/hành vi |
Ví dụ về giao diện trong Java 8+
public interface MayTinh {
// Hằng số ngầm định
double PI = 3.14159;
// Phương thức trừu tượng
double tinhToan(double a, double b);
// Phương thức mặc định (Java 8)
default void hienThiThongSo() {
System.out.println("Máy tính với PI = " + PI);
}
// Phương thức tĩnh (Java 8)
static String phienBan() {
return "MayTinh v2.0";
}
}
Lưu ý quan trọng về quy tắc
- Ghi đè (Override): Cùng tên, cùng tham số, cùng kiểu trả về (hoặc kiểu con). Dùng
@Overrideđể kiểm tra. - Nạp chồng (Overload): Cùng tên, khác tham số (số lượng/khác kiểu). Kiểu trả về không quyết định nạp chồng.
- Thứ tự khởi tạo: Khối tĩnh → Biến tĩnh → Khối khởi tạo → Constructor.
- Lớp con không kế thừa được thành phần
privatecủa lớp cha.