Inheritance
Duy Văn | 11/03/2025
Inheritance hay kế thừa là một trong những khái niệm quan trọng nhất trong lập trình hướng đối tượng, nó cho phép một class mới có thể kế thừa các thuộc tính và phương thức từ một class đã tồn tại, nó cũng là nền móng cho abstraction và encapsulation, nhưng mình nói về inheritance sau cũng chính là để nhấn mạnh tính quan trọng của nó. Ở bài Abstraction với Abstraction và Interface, rồi ở bài Encapsulation, rõ ràng là cách ứng dụng của chúng cần dùng đến tính kế thừa
Vậy thì kế thừa hiểu đơn giản là ứng dụng để cho phép tạo ra các class con từ class cha, kế thừa từ class cha một số hoặc tất cả thuộc tính và method
Cú pháp như sau
class Vehicle{
protected String brand = "Ford";
public void honk(){
System.out.println("Tutu");
}
}
class Mustang extends Vehicle{
private String modelName = "Mustang";
public static void main(String[] args){
Mustang myCar = new Mustang()
myCar.honk();
System.out.println(myCar.brand + " " + myCar.modelName);
}
}
Mutiple Inheritance
Đa kế thừa có thể được làm trong Java, hiểu nôm na là một class con có nhiều class cha, mẹ. Và tuỳ theo cấu trúc dữ liệu và context của code mà có một số pattern kế thừa như:
Multi level
GrandParent
|
|
Parent1
|
|
Test
Ví dụ
// Grandparent class
class Animal {
void makeSound() {
System.out.println("Animal makes a sound");
}
}
// Parent class inheriting from Animal
class Mammal extends Animal {
void eat() {
System.out.println("Mammal eats");
}
}
// Child class inheriting from Mammal
class Dog extends Mammal {
void bark() {
System.out.println("Dog barks");
}
}
Có thể thực hiện với nhiều level kế thừa chứ không chỉ dừng ở 2
Hierarchical
Parent
/ \
/ \
Child1 Child2
Ví dụ
// Parent class
class Animal {
void makeSound() {
System.out.println("Animal makes a sound");
}
}
// Child class 1 inheriting from Animal
class Dog extends Animal {
void bark() {
System.out.println("Dog barks");
}
}
// Child class 2 inheriting from Animal
class Cat extends Animal {
void meow() {
System.out.println("Cat meows");
}
}
Multiple parent
Parent1 Parent2
\ /
\ /
Test
Ví dụ
// Interface 1
interface Parent1 {
default void dance() {
System.out.println("Dance");
}
}
// Interface 2
interface Parent2 {
default void run() {
System.out.println("run");
}
}
// Implementing multiple interfaces
class Test implements Parent1, Parent2 {
public static void main(String args[]) {
Test t = new Test();
t.run();
t.dance();
}
}
Vấn đề với multiple parent Tuy nhiên sẽ có vấn đề với một kiểu pattern như Diamond, khi mà cả cha và mẹ hay các class cha có cùng tên method:
GrandParent
/ \
/ \
Parent1 Parent2
\ /
\ /
Test
Với ví dụ sau
// First Parent Class
class Parent1 {
void fun() { System.out.println("Parent1"); }
}
// Second Parent Class
class Parent2 {
void fun() { System.out.println("Parent2"); }
}
// Inheriting Properties of
// Parent1 and Parent2
class Test extends Parent1, Parent2
{
// main method
public static void main(String args[])
{
// Creating instance of Test
Test t = new Test();
t.fun();
}
}
Compile sẽ lỗi do bản chất phía Java không như Python, Python có MRO - Method Resolution Order, còn Java thì không, thế nên ở trong code này chúng ta cần phải quyết định nên chọn fun() của parent nào. Chúng ta cần chuyển các class thành interface,
// First Parent Interface
interface Parent1 {
default void fun() { System.out.println("Parent1"); }
}
// Second Parent Interface
interface Parent2 {
default void fun() { System.out.println("Parent2"); }
}
// Inheriting Properties of
// Parent1 and Parent2
class Test implements Parent1, Parent2
{
@Override
public void fun(){
Parent1.super.fun();
Parent2.super.fun();
}
// Ví dụ : fun() của class con sẽ chạy cả fun() của 2 parents
// main method
public static void main(String args[])
{
// overide
// Creating instance of Test
Test t = new Test();
t.fun();
}
}