Trong các bài trước, chúng ta đã làm việc sơ qua với tính năng thừa kế trong Java. Trong Java thì các lớp có thể thừa kế lại các lớp khác, tức là có chứa các thuộc tính và phương thức của các lớp khác.
Một lớp kế thừa từ lớp khác còn được gọi là subclass (hoặc lớp con). Lớp được các lớp khác kế thừa lại thì được gọi là superclass (hay lớp cha hoặc lớp cơ cở).
Mặc định trong Java thì toàn bộ các lớp, kể cả lớp được định nghĩa bởi lập trình viên, nếu không khai báo kế thừa từ lớp nào thì đều được kế thừa từ một lớp gốc có tên là Object
.
Các lớp cũng có thể được kế thừa từ một lớp đã được kế thừa, cứ như vậy, và tất nhiên lớp cha cao nhất là lớp Object
.
Tính năng thừa kế là một tính năng rất mạnh mẽ, nó cho phép chúng ta tạo thêm lớp mới nhưng không cần viết các đoạn code đã có sẵn trong các lớp khác, chúng ta chỉ cần “kế thừa” lại và viết thêm các đoạn code mới.
Một lớp con kế thừa toàn bộ các thuộc tính, phương thức và các lớp lồng nhau của lớp cha. Tuy nhiên không kế thừa phương thức khởi tạo (constructor), nhưng chúng ta có thể gọi phương thức khởi tạo của lớp cha trong lớp con.
Cây phân lớp Java
Lớp Object
được định nghĩa trong gói java.lang
định nghĩa tất cả các hành vi của toàn bộ các lớp, kể cả các lớp mà chúng ta tự viết. Trong Java thì có một số lớp kế thừa trực tiếp từ lớp Object
, và một số lớp khác lại kế thừa từ các lớp này, tạo thành một cây phân cấp các lớp.
Ví dụ
Chẳng hạn chúng ta có đoạn code định nghĩa lớp Bicycle
như sau:
public class Bicycle { private int gear; private int speed; public Bicycle(int gear, int speed) { this.gear = gear; this.speed = speed; } public int getGear() { return gear; } public void setGear(int newValue) { gear = newValue; } public int getSpeed() { return speed; } public void speedUp(int increment) { speed += increment; } }
Lớp Bicycle
có 2 thuộc tính và 4 phương thức. Trong đó phương thức Bicycle()
là phương thức khởi tạo, phương thức này nhận vào 2 tham số là speed
và gear
dùng để gán cho 2 thuộc tính speed
và gear
.
Sau đó chúng ta định nghĩa lớp MountainBike
kế thừa lớp Bicycle
như sau:
public class MountainBike extends Bicycle { public int seatHeight; public MountainBike(int startHeight, int speed, int gear) { super(seatHeight, speed, gear); seatHeight = startHeight; } public void setHeight(int newValue) { seatHeight = newValue; } }
Chúng ta cho lớp MountainBike
kế thừa từ lớp Bicycle
bằng cách thêm từ khóa extends Bicycle
vào sau tên MountainBike
. Bên trong chúng ta định nghĩa thêm thuộc tính seatHeight
, 2 phương thức MountainBike()
và setHeight()
. Phương thức khởi tạo MountainBike()
nhận vào các tham số seatHeight
, speed
và gear
, chúng ta không gán giá trị trực tiếp cho các thuộc tính speed
và gear
của lớp MountainBike
, mà thay vào đó chúng ta gọi phương thức khởi tạo của lớp cha là super()
và truyền vào các giá trị speed
và gear
. Phương thức super()
sẽ gọi phương thức khởi tạo của lớp Bicycle()
, và như thế thì các giá trị speed
và gear
của lớp MountainBike
sẽ được gán luôn trong đó
Quyền thừa kế của lớp con
- Lớp con kế thừa toàn bộ các phương thức và thuộc tính có phạm vi public và protected của lớp cha. Nếu lớp con nằm chung gói (package) với lớp cha thì sẽ kế thừa cả các thuộc tính và phương thức private.
- Có thể định nhĩa thuộc tính và phương thức mới.
- Các thuộc tính và phương thức được thừa kế được sử dụng trực tiếp như các thuộc tính và phương thức bình thường.
- Có thể định nghĩa thuộc tính trong lớp con trùng tên với thuộc tính trong lớp cha, tuy nhiên thông thường chúng ta không nên làm thế.
- Có thể định nghĩa phương thức trong lớp con trùng tên với phương thức trong lớp cha, việc này còn được gọi là ghi đè (overriding).
- Có thể định nghĩa phương thức static trùng tên.
Các thành phần private
Một lớp con không được thừa kế các thành phần private của lớp cha. Tuy nhiên nếu lớp cha có phương thức public hoặc protected mà có sử dụng đến các thành phần private thì lớp con cũng có thể gọi các phương thức này.
Ép kiểu đối tượng
Các đối tượng thuộc lớp cha có thể sử dụng phương thức khởi tạo của các lớp con. Tức là chúng ta có thể tạo đối tượng Bicycle
như sau:
Bicycle bike = new MountainBike(); Object obj = new Bicycle(); ...
Trường hợp ngược lại thì không được phép trong Java. Nếu chúng ta viết:
MoutainBike bike = new Bibycle();
Thì trình biên dịch sẽ báo lỗi. Tuy nhiên chúng ta có thể ép kiểu:
MountainBike bike = (Bicycle)new Bicycle();