Tính kế thừa trong Java (inheritance) là một trong những khái niệm cốt lõi của Lập trình hướng đối tượng . Nó được sử dụng khi có mối quan hệ “is-a” giữa các đối tượng. Inheritance trong Java được triển khai bằng từ khóa extends.

Inheritance trong Java
- Kế thừa trong Java là một phương pháp để tạo ra hệ thống phân cấp giữa các lớp (class) bằng cách kế thừa từ các lớp khác.
- Kế thừa trong Java có tính chất bắc cầu (transitive) – nếu
Sedankế thừa từCarvàCarkế thừa từVehicle, thìSedancũng kế thừa từ lớpVehicle. LớpVehicletrở thành siêu lớp (superclass) của cảCarvàSedan. - Kế thừa được sử dụng rộng rãi trong các ứng dụng Java. Ví dụ, việc mở rộng lớp
Exceptionđể tạo một lớpExceptioncụ thể cho ứng dụng, chứa nhiều thông tin hơn như mã lỗi. Một ví dụ khác làNullPointerException.
Ví dụ về Inheritance trong Java
Mọi lớp trong Java đều ngầm định (implicitly) kế thừa từ lớp java.lang.Object. Do đó, lớp Object nằm ở cấp cao nhất của hệ thống phân cấp kế thừa trong Java.
Bây giờ, hãy cùng xem cách triển khai kế thừa trong Java với một ví dụ đơn giản.
Superclass: Animal
package com.journaldev.inheritance;
public class Animal {
private boolean vegetarian;
private String eats;
private int noOfLegs;
public Animal(){}
public Animal(boolean veg, String food, int legs){
this.vegetarian = veg;
this.eats = food;
this.noOfLegs = legs;
}
public boolean isVegetarian() {
return vegetarian;
}
public void setVegetarian(boolean vegetarian) {
this.vegetarian = vegetarian;
}
public String getEats() {
return eats;
}
public void setEats(String eats) {
this.eats = eats;
}
public int getNoOfLegs() {
return noOfLegs;
}
public void setNoOfLegs(int noOfLegs) {
this.noOfLegs = noOfLegs;
}
}
Trong ví dụ này, Animal là lớp cơ sở. Bây giờ, chúng ta sẽ tạo một lớp Cat kế thừa từ lớp Animal. Subclass: Cat
package com.journaldev.inheritance;
public class Cat extends Animal{
private String color;
public Cat(boolean veg, String food, int legs) {
super(veg, food, legs);
this.color="White";
}
public Cat(boolean veg, String food, int legs, String color){
super(veg, food, legs);
this.color=color;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
Lưu ý rằng chúng ta đang sử dụng từ khóa extends để triển khai inheritance trong Java.
Chương trình kiểm tra kế thừa trong Java
Bây giờ, chúng ta hãy viết một lớp kiểm tra đơn giản để tạo một đối tượng Cat và sử dụng một số phương thức của nó.
package com.journaldev.inheritance;
public class AnimalInheritanceTest {
public static void main(String[] args) {
Cat cat = new Cat(false, "milk", 4, "black");
System.out.println("Cat is Vegetarian?" + cat.isVegetarian());
System.out.println("Cat eats " + cat.getEats());
System.out.println("Cat has " + cat.getNoOfLegs() + " legs.");
System.out.println("Cat color is " + cat.getColor());
}
}
Kết quả:

Lớp Cat không có phương thức getEats() nhưng chương trình vẫn hoạt động vì phương thức này được kế thừa từ lớp Animal.
Các điểm quan trọng
- Tái sử dụng code (Code reuse) là lợi ích quan trọng nhất của kế thừa, vì các lớp con (subclass) sẽ kế thừa các biến và phương thức của lớp cha (superclass).
- Các thành viên
privatecủa lớp cha không thể truy cập trực tiếp từ lớp con. Giống như trong ví dụ trên, biếnnoOfLegscủa lớpAnimalkhông thể truy cập trực tiếp từ lớp `Cat, nhưng có thể truy cập gián tiếp thông qua các phương thức getter và setter. - Các thành viên của lớp cha có mức truy cập
defaultchỉ có thể truy cập được bởi lớp con nếu chúng ở trong cùng một package. - Các hàm constructor của lớp cha không được kế thừa bởi lớp con.
- Nếu lớp cha không có hàm khởi tạo mặc định, thì lớp con cũng cần phải định nghĩa một hàm khởi tạo tường minh (explicit constructor). Nếu không, chương trình sẽ báo lỗi khi biên dịch (compile time exception). Trong trường hợp này, việc gọi hàm khởi tạo của lớp cha bằng từ khóa
superlà bắt buộc và phải là câu lệnh đầu tiên trong hàm khởi tạo của lớp con. - Java không hỗ trợ đa kế thừa (multiple inheritance), một lớp con chỉ có thể kế thừa từ một lớp duy nhất. Lớp
Animalngầm định kế thừa từ lớpObjectvàCatkế thừa từAnimal, nhưng nhờ tính chất bắc cầu của kế thừa trong Java, lớpCatcũng kế thừa từ lớpObject. - Chúng ta có thể tạo một instance của lớp con và gán nó cho một biến của lớp cha, đây được gọi là upcasting. Dưới đây là một ví dụ đơn giản về upcasting:
Cat c = new Cat(); //subclass instance
Animal a = c; //upcasting, it's fine since Cat is also an Animal
- Khi một thể hiện (instance) của lớp cha được gán cho một biến của lớp con, quá trình này được gọi là downcasting. Chúng ta cần phải ép kiểu tường minh biến đó sang lớp con. Ví dụ:
Cat c = new Cat();
Animal a = c;
Cat c1 = (Cat) a; //explicit casting, works fine because "c" is actually of type Cat
Lưu ý rằng trình biên dịch sẽ không báo lỗi ngay cả khi chúng ta thực hiện việc downcasting sai, bởi vì chúng ta đã ép kiểu tường minh. Tuy nhiên, trong một số trường hợp dưới đây, chương trình sẽ báo lỗi ClassCastException khi chạy:
Dog d = new Dog();
Animal a = d;
Cat c1 = (Cat) a; //ClassCastException at runtime
Animal a1 = new Animal();
Cat c2 = (Cat) a1; //ClassCastException because a1 is actually of type Animal at runtime
- Trong một lớp con, chúng ta có thể ghi đè một phương thức của lớp cha. Tuy nhiên, chúng ta nên luôn chú thích phương thức bị ghi đè với
@Override. Điều này giúp trình biên dịch biết rằng chúng ta đang ghi đè một phương thức, và nếu có bất kỳ thay đổi nào trong phương thức của lớp cha, chúng ta sẽ nhận được lỗi lúc biên dịch thay vì nhận kết quả không mong muốn lúc chạy. - Chúng ta có thể gọi các phương thức và truy cập các biến của lớp cha bằng từ khóa
super. Điều này rất hữu ích khi lớp con có một biến hoặc phương thức cùng tên với lớp cha, nhưng chúng ta muốn truy cập phiên bản của lớp cha.supercũng được dùng để gọi tường minh hàm khởi tạo của lớp cha khi cả hai lớp đều có định nghĩa hàm khởi tạo. - Chúng ta có thể dùng lệnh
instanceofđể kiểm tra mối quan hệ kế thừa giữa các đối tượng. Hãy cùng xem ví dụ dưới đây.
Cat c = new Cat(); Dog d = new Dog(); Animal an = c;
boolean flag = c instanceof Cat; //normal case, returns true
flag = c instanceof Animal; // returns true since c is-an Animal too
flag = an instanceof Cat; //returns true because a is of type Cat at runtime
flag = an instanceof Dog; //returns false for obvious reasons.
1. Chúng ta không thể kế thừa các lớp `final` trong Java.
2. Nếu lớp cha chỉ được dùng làm cơ sở để chứa các đoạn code có thể tái sử dụng mà không cần khởi tạo đối tượng, chúng ta có thể khai báo nó là một lớp trừu tượng (`Abstract class`). Điều này sẽ giúp tránh việc các lớp khác khởi tạo không cần thiết các đối tượng từ lớp cơ sở. Nó cũng hạn chế việc tạo các thể hiện từ lớp cơ sở.
Bạn có thể xem thêm nhiều ví dụ về inheritance (kế thừa) trong Java từ [GitHub Repository](<https://github.com/journaldev/journaldev/tree/master/CoreJavaProjects/CoreJavaExamples/src/com/journaldev/inheritance>) của chúng tôi.
Tham khảo: [Oracle Documentation.](<https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html>)