Java Core - Tính đa hình trong java

Tính đa hình trong java

Đa hình trong java (Polymorphism) là một khái niệm mà chúng ta có thể thực hiện một hành động bằng nhiều cách khác nhau. Polymorphism được cấu tạo từ 2 từ Hy Lạp: poly và morphs. Trong đó “poly” có nghĩa là nhiều và “morphs” có nghĩa là hình thể. Vậy polymorphism có nghĩa là nhiều hình thể.

Có hai kiểu của đa hình trong java, đó là đa hình lúc biên dịch (compile) và đa hình lúc thực thi (runtime). Chúng ta có thể thực hiện đa hình trong java bằng cách nạp chồng phương thức và ghi đè phương thức.

Nếu bạn nạp chồng phương thức static trong java, đó là một ví dụ về đa hình lúc biên dịch. Trong bài này, chúng ta tập trung vào đa hình lúc runtime trong java.

Đa hình lúc runtime trong java

Đa hình lúc runtime là quá trình gọi phương thức đã được ghi đè trong thời gian thực thi chương trình. Trong quá trình này, một phương thức được ghi đè được gọi thông qua biến tham chiếu của một lớp cha.

Trước khi tìm hiểu về đa hình tại runtime, chúng ta cùng tìm hiểu về Upcasting.


Upcasting là gì?

Khi biến tham chiếu của lớp cha tham chiếu tới đối tượng của lớp con, thì đó là Upcasting. Ví dụ:

class A{}  
class B extends A{}  
A a=new B();//upcasting  

Ví dụ về đa hình lúc runtime trong java

Ví dụ 1:

Chúng ta tạo hai lớp Bike và Splendar. Lớp Splendar kế thừa lớp Bike và ghi đè phương thức run() của nó. Chúng ta gọi phương thức run bởi biến tham chiếu của lớp cha. Khi nó tham chiếu tới đối tượng của lớp con và phương thức lớp con ghi đè phương thức của lớp cha, phương thức lớp con được gọi lúc runtime.

Khi việc gọi phương thức được quyết định bởi JVM chứ không phải Compiler, vì thế đó là đa hình lúc runtime.

class Bike {
	void run() {
		System.out.println("Chạy");
	}
}

public class motorbike extends Bike {

	void run() {
		System.out.println("Chạy khoảng 40km/giờ");
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Bike bk = new motorbike();
		System.out.println("Ví dụ về tính đa hình:");
		bk.run();
	}

}

Kết quả:

Ví dụ 2: Bank:

Giả sử Bank là một lớp cung cấp chức năng xem thông tin tỷ lệ lãi suất. Nhưng mỗi ngân hàng có một lãi xuất khác nhau, ví dụ các ngân hàng SBI, ICICI và AXIS có tỷ lệ lãi suất lần lượt là 8%, 7% và 9%.

class Bank {
	int getRateOfInterest() {
		return 0;
	}
}

class Vietcombank extends Bank {
	int getRateOfInterest() {
		return 8;
	}
}

class BIDV extends Bank {
	int getRateOfInterest() {
		return 7;
	}
}

class MB extends Bank {
	int getRateOfInterest() {
		return 9;
	}
}

public class tinhdahinh02 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Bank b;
		b = new Vietcombank();
		System.out.println("Ví dụ về tính đa hình:");
		System.out.println("Vietcombank Rate of Interest: " + b.getRateOfInterest());
		b = new BIDV();
		System.out.println("BIDV Rate of Interest: " + b.getRateOfInterest());
		b = new MB();
		System.out.println("MB Rate of Interest: " + b.getRateOfInterest());
	}

}

Kết quả:

Ví dụ 3: Shape:

class Shape {
	void draw() {
		System.out.println("Drawing...");
	}
}

class Rectangle extends Shape {
	void draw() {
		System.out.println("Drawing rectangle...");
	}
}

class Circle extends Shape {
	void draw() {
		System.out.println("Drawing circle...");
	}
}

class Triangle extends Shape {
	void draw() {
		System.out.println("Drawing triangle...");
	}
}

public class tinhdahinh03 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Shape s;
		System.out.println("Ví dụ về tính đa hình:");
		s = new Rectangle();
		s.draw();
		s = new Circle();
		s.draw();
		s = new Triangle();
		s.draw();

	}

}

Kết quả:


Đa hình lúc runtime trong Java với thành viên dữ liệu

Phương thức bị ghi đè không là thành viên dữ liệu, vì thế đa hình tại runtime không thể có được bởi thành viên dữ liệu. Trong ví dụ sau đây, cả hai lớp có một thành viên dữ liệu là speedlimit, chúng ta truy cập thành viên dữ liệu bởi biến tham chiếu của lớp cha mà tham chiếu tới đối tượng lớp con. Khi chúng ta truy cập thành viên dữ liệu mà không bị ghi đè, thì nó sẽ luôn luôn truy cập thành viên dữ liệu của lớp cha.

Quy tắc: Đa hình lúc runtime không thể xảy ra với thành viên dữ liệu.

class Bike {
	int speedlimit = 90;
}

public class Supper_Cup_50 extends Bike {
	int speedlimit = 150;

	public static void main(String[] args) {
		System.out.println("Vi du ve tinh da hinh:");
		Bike obj = new Supper_Cup_50();
		System.out.println(obj.speedlimit);// 90
	}
}

Kết quả:

Đa hình lúc runtime trong Java với kế thừa nhiều tầng

Ví dụ 1:

class Animal {
	void eat() {
		System.out.println("Eating");
	}
}

class Dog extends Animal {
	void eat() {
		System.out.println("Eating fruits");
	}
}

public class tinhdahinh05 extends Dog {
	void eat() {
		System.out.println("Drinking milk");
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Animal a1, a2, a3;
		System.out.println("Ví dụ về tính đa hình:");
		a1 = new Animal();
		a2 = new Dog();
		a3 = new tinhdahinh05();
		a1.eat();
		a2.eat();
		a3.eat();

	}
}

Kết quả:

Ví dụ 2:

class Animal {
	void eat() {
		System.out.println("Animal is eating...");
	}
}

class Dog extends Animal {
	void eat() {
		System.out.println("Dog is eating...");
	}
}

public class tinhdahinh06 extends Dog {
	public static void main(String args[]) {
		// TODO Auto-generated method stub

		System.out.println("Ví dụ về tính đa hình:");
		Animal a = new tinhdahinh06();
		a.eat();
	}

}

Kết quả:

Vì BabyDog1 không ghi đè phương thức eat(), nên phương thức eat() của lớp Dog được gọi.