1. Kế thừa (inheritance) là gì?
Bản chất kế thừa (inheritance) là phát triển lớp mới dựa trên các lớp đã có. Xây dựng các lớp mới có sẵn các đặc tính của lớp cũ, đồng thời lớp mới có thể mở rộng các đặc tính của nó.
Ví dụ:
Lớp Người có các thuộc tính như tên, tuổi, chiều cao, cân nặng,…; các phương thức như ăn, ngủ, chơi,…
Lớp Sinh Viên thừa kế từ lớp Người, thừa kế được các thuộc tính tên, tuổi, chiều cao, cân nặng,…; các phương thức ăn, ngủ, chơi,…Bổ sung thêm các thuộc tính như mã số sinh viên, số tín chỉ tích lũy,…, các phương thức như tham dự lớp học, thi…
Lớp kế thừa gọi là lớp con (child, subclass), lớp dẫn xuất (derived class). Lớp được kế thừa gọi là lớp cha (parent, superclass), lớp cơ sở (base class).
Mối quan hệ kế thừa: Lớp con là một loại (is-a-kind-of) của lớp cha, kế thừa các thành phần dữ liệu và các hành vi của lớp cha. Có thể khai báo thêm thuộc tính, phương thức cho phù hợp với mục đích sử dụng mới.
Ví dụ: Lớp SinhVien kế thừa từ lớp Nguoi, lớp GiaoVien kế thừa từ lớp Nguoi thì một đối tượng SinhVien là một Nguoi, một đối tượng GiaoVien là một Nguoi. Nhưng một đối tượng Nguoi chưa chắc là SinhVien bởi vì có thể đối tượng Nguoi đó là GiaoVien. Tương tự, môt đối tượng Nguoi chưa chắc là GiaoVien bởi vì có thể đối tượng Nguoi đó là SinhVien.
Bản chất kế thừa là một kỹ thuật tái sử dụng mã nguồn thông qua lớp.
Ví dụ: Lớp SinhVien tái sử dụng được các thuộc tính như tên, tuổi… và các phương thức của lớp Nguoi.
2. Khai báo kế thừa (inheritance) trong Java
Cú pháp:
<Lớp con> extends <Lớp cha>{
//thân lớp con
}
Ví dụ:
class Nguoi {
String name;
//hàm đi chơi
void diChoi(){
System.out.println(name + " di choi thoi!");
}
}
class SinhVien extends Nguoi {
int studentId;
//hàm đi học
void diHoc(){
System.out.println(name + " mssv: " + studentId + " di hoc thoi!");
}
}
public class Main {
public static void main(String args[]){
SinhVien sv1 = new SinhVien();
sv1.name = "An";
sv1.studentId = 123456789;
sv1.diChoi();
sv1.diHoc();
}
}
Kết quả
An di choi thoi!
An mssv: 123456789 di hoc thoi!
Trong ví dụ trên, lớp SinhVien kế thừa từ lớp Nguoi. Lớp SinhVien kế thừa thuộc tính String name
và hàm diChoi()
từ lớp Nguoi.
Một câu hỏi đặt ra là lớp con kế thừa được những gì từ lớp cha?
Lớp con kế thừa các thành viên được khai báo là public, protected và mặc định (default) của lớp cha. Không kế thừa được các thành viên private.
Các bạn nên đọc bài Chỉ định truy cập (access modifier) của thành viên thuộc lớp trong Java để hiểu rõ về các access modifier trong Java là default, private, protected và public.
Bảng phạm vi truy cập và nguyên lý kế thừa trong Java
public | protected | mặc định | private | |
Cùng lớp | ✔ | ✔ | ✔ | ✔ |
Lớp bất kỳ cùng gói | ✔ | ✔ | ✔ | ✘ |
Lớp con khác gói | ✔ | ✔ | ✘ | ✘ |
Lớp bất kỳ khác gói | ✔ | ✘ | ✘ | ✘ |
Bảng này giống như “khẩu quyết nội công tâm pháp”, các bạn phải ngẫm nghĩ, bắt buộc phải nhớ rõ và hiểu nó.
class LopCha{
private String bienA;//biến private
String bienB;//biến default
protected int bienC;//biến protected
public int bienD;//biến public
private void ham1(){//hàm private
System.out.println("Ham private.");
}
void ham2(){//hàm default
System.out.println("Ham default.");
}
protected void ham3(){////hàm protected
System.out.println("Ham protected.");
}
public void ham4(){//hàm public
System.out.println("Ham public.");
}
}
class LopCon extends LopCha{
}
public class Test{
public static void main(String[] args) {
LopCon a = new LopCon();
a.bienA = "abc";//lỗi, không kế thừa được biến private
a.bienB = "xyz";//kế thừa được biến default
a.bienC = 9;//kế thừa được biến protected
a.bienD = 9;//kế thừa được biến public
a.ham1();//lỗi, không kế thừa được hàm private
a.ham2();//kế thừa được hàm default
a.ham3();//kế thừa được hàm protected
a.ham4();//kế thừa được hàm public
}
}
Các phương thức không được phép kế thừa:
– Các phương thức khởi tạo và hủy:
- Làm nhiệm vụ khởi tạo và gỡ bỏ các đối tượng.
- Chúng chỉ biết cách làm việc với từng lớp cụ thể.
– Toán tử gán “=”, làm nhiệm vụ giống như phương thức khởi tạo.
3. Các loại kế thừa trong Java
Đơn kế thừa (single inheritance)
Một lớp con kế thừa từ một lớp cha.
Kế thừa nhiều cấp (multilevel inheritance)
Một lớp con kế thừa từ một lớp cha. Lớp cha đó lại kế thừa từ một lớp khác.
Kế thừa phân cấp (hierarchical inheritance)
Nhiều lớp con kế thừa từ một lớp cha. Các lớp con có cùng lớp cha gọi là các lớp anh chị em (siblings).
Java không hỗ trợ đa kế thừa (multiple Inheritance)
Trong Java không hỗ trợ đa kế thừa, tức là một lớp con kế từ từ nhiều lớp cha.
Nhưng trong Java có thể thực hiện đa kế thừa bằng cách sử dụng interface, chứ không đa kế thừa từ lớp (class) được để tránh những mơ hồ không cần thiết khi kế thừa.
Kế thừa lai (hybrid inheritance)
Kế thừa lai là sự kế hợp giữa 2 hoặc nhiều hơn 2 loại kế thừa.
Ở trên là ví dụ kết hợp giữa kế thừa phần cấp và đa kế thừa (phải sử dụng interface).
Lưu ý:
Nếu một lớp không được định nghĩa là lớp con của một lớp khác thì mặc định nó là lớp con trực tiếp của lớp Object
. Lớp này được định nghĩa trong package
chuẩn java.lang
, chứa một số phương thức hữu ích kế thừa lại cho tất cả các lớp.
4. Khai báo và hủy đối tượng (object) trong kế thừa
Khởi tạo đối tượng: Lớp cha được khởi tạo trước lớp con. Các phương thức khởi tạo của lớp con luôn gọi phương thức khởi tạo của lớp cha ở câu lệnh đầu tiên.
- Tự động gọi (ngầm định – implicit): khi lớp cha có phương thức khởi tạo mặc định.
- Gọi trực tiếp (tường minh – explicit): sử dụng từ khóa super.
class TuGiac {
public TuGiac() {
System.out.println("Lop cha TuGiac()");
}
}
class HinhVuong extends TuGiac {
public HinhVuong() {
// Tu dong goi TuGiac()
System.out.println("Lop con HinhVuong()");
}
}
public class Test {
public static void main(String arg[]) {
HinhVuong hv = new HinhVuong();
}
}
Kết quả
Lop cha TuGiac()
Lop con HinhVuong()
Hủy bỏ đối tượng: Ngược lại so với khởi tạo đối tượng.