Tính đa hình (polymorphism) trong Java

Đây là bài 33/62 bài của series môn học Ngôn ngữ lập trình Java

1. Tính đa hình (polymorphism) trong Java là gì?

Tính đa hình (polymorphism) hiểu đơn giản là các đối tượng, các phương thức giống nhau có thể có các hành vi khác nhau tùy vào từng tình huống khác nhau.

class Polygon {
  //phương thức render của lớp Polygon
  public void render() {
    System.out.println("Rendering Polygon...");
  }
}

class Square extends Polygon {
  //ghi đè phương thức render
  @Override
  public void render() {
    System.out.println("Rendering Square...");
  }
}

class Circle extends Polygon {
  //ghi đè phương thức render
  @Override
  public void render() {
    System.out.println("Rendering Circle...");
  }
}

class Main {
  public static void main(String[] args) {
    // create an object of Square
    Square s1 = new Square();
    s1.render();

    // create an object of Circle
    Circle c1 = new Circle();
    c1.render();
  }
}
Kết quả
Rendering Square...
Rendering Circle...

Ở ví dụ trên, lớp Polygon có 2 lớp con là Square and Circle. Chúng đều có hàm render() nhưng hàm này thực thi khác nhau trong từng lớp. Đó là biểu hiện của tính đa hình (polymorphism).

2. Tại sao sử dụng tính đa hình (polymorphism)

Tính đa hình (polymorphism) trong Java cho phép chúng ta tạo ra những mã code nhất quán. Lấy ví dụ ở phần 1, chúng ta có thể tạo ra các hàm render với các tên khác nhau như renderSquare()renderCircle() cho từng lớp SquareCircle.

Chương trình của bạn cũng sẽ hoạt động tốt thôi nhưng việc tạo ra các tên khác nhau cho một hàm có chức năng giống nhau thì sẽ làm code không nhất quán, rườm rà, cồng kềnh.

Tính đa hình cho phép chúng ta tạo ra một hàm tên là render() duy nhất nhưng sẽ thực thi khác nhau với từng lớp khác nhau.

Trong Java, chúng ta có thể đạt được tính đa hình (polymorphism) với nạp chồng phương thức (method overloading), ghi đè phương thức (method overriding).

Lưu ý: Trong Java không hỗ trợ lập trình viên tự định nghĩa nạp chồng toán tử (operator overloading) như trong C++.

3. Chuyển đổi kiểu dữ liệu đối tượng

Kiểu dữ liệu tham chiếu (các lớp) có thể được chuyển đổi kiểu khi kiểu dữ liệu tham chiếu (lớp) tương thích, tức là nằm trên cùng một cây phân cấp kế thừa.

Cây phân cấp kế thừa Java

Có hai cách chuyển đổi là Up-castingDown-casting.

Up-casting

– Đi lên trên cây phân cấp thừa kế. Up-casting là khả năng nhìn nhận đối tượng thuộc lớp dẫn xuất như là một đối tượng thuộc lớp cơ sở.

– Tự động chuyển đổi kiểu.

Ví dụ:

Ví dụ cây kế thừa person employee
class Person{
    String name;
    Date birthday;
    public void setName(String name){
        this.name = name;
    }
    public void setBirthday(Date birthday){
        this.birthday = birthday;
    }
    public String getDetails(){
        String detail = "";
        detail = "Name: " + name + ", birthday: " + new SimpleDateFormat("MM-dd-yyyy").format(birthday);
        
        return detail;
    }
}

class Employee extends Person{
    double salary;
    public void setSalary(double salary){
        this.salary = salary;
    }
    @Override
    public String getDetails(){
        String detail="";
        detail = "Name: " + name + ", birthday: " + new SimpleDateFormat("MM-dd-yyyy").format(birthday) + ", salary: " + salary;
        
        return detail;
    }
}

class Main {
    public static void main(String[] args) throws ParseException {
        Employee e = new Employee();
        Person p;
        p = e;
        p.setName("Henry");
        p.setBirthday(new SimpleDateFormat("MM-dd-yyyy").parse("12-31-1998"));
        System.out.println(p.getDetails());   
    }
}
Kết quả
Name: Henry, birthday: 12-31-1998, salary: 0.0

Trong ví dụ trên, chúng ta tạo ra đối tượng p của lớp Person. Mà lớp Person là lớp cha của lớp Employee. Một Employee cũng là một Person. Nên p có thể tham chiếu đến đối tượng của lớp Employee với câu lệnh p = e;. Các hàm mà Person p gọi là những hàm mà một Employee kế thừa được từ Person.

Lưu ý, một Person chưa chắc là một Employee bởi có thể có những lớp khác cũng kế thừa lớp Person như lớp Student, Teacher. Thì lúc này, Person cũng có thể là Student hay Teacher. Nhưng một Student hay Teacher thì chắc chắn vẫn là một Person.

Lưu ý tiếp theo, nếu đối tượng p của lớp Person gọi hàm setSalary() của đối tượng e thuộc lớp Employee thì sẽ báo lỗi. Bởi vì một đối tượng người thì không có setSalary(). Tức là, Employee e bây giờ là 1 Person bình thường.

p.setSalary(7000.0);//error

Down-casting

– Đi xuống cây phân cấp thừa kế. Down-casting là khả năng nhìn nhận một đối tượng thuộc lớp cơ sở như một đối tượng thuộc lớp dẫn xuất.

– Không tự động chuyển đổi kiểu, phải ép kiểu.

class Person{
    String name;
    Date birthday;
    public void setName(String name){
        this.name = name;
    }
    public void setBirthday(Date birthday){
        this.birthday = birthday;
    }
    public String getDetails(){
        String detail = "";
        detail = "Name: " + name + ", birthday: " + new SimpleDateFormat("MM-dd-yyyy").format(birthday);
        
        return detail;
    }
}

class Employee extends Person{
    double salary;
    public void setSalary(double salary){
        this.salary = salary;
    }
    @Override
    public String getDetails(){
        String detail="";
        detail = "Name: " + name + ", birthday: " + new SimpleDateFormat("MM-dd-yyyy").format(birthday) + ", salary: " + salary;
        
        return detail;
    }
}

class Main {
    public static void main(String[] args) throws ParseException {
        Person p1 = new Employee();
        //down-casting
        Employee e1 = (Employee) p1;
        e1.setName("Henry");
        e1.setBirthday(new SimpleDateFormat("MM-dd-yyyy").parse("12-31-1998"));
        e1.setSalary(7000.0);
        System.out.println(e1.getDetails());
    }
}
Kết quả
Name: Henry, birthday: 12-31-1998, salary: 7000.0

Tóm lại, Up-casting là gán object của lớp con cho biến tham chiếu của lớp cha. Down-casting là gán object của lớp cha cho biến tham chiếu của lớp con.

4. Toán tử instanceof

Toán tử instanceof trong Java được sử dụng để kiểm tra một đối tượng có phải là thể hiện của một kiểu dữ liệu (lớp) nào đó hay không.

instanceof trong Java được gọi là toán tử so sánh kiểu. Nó trả về giá trị boolean true hoặc false. Nếu bạn dùng toán tử instanceof với bất kỳ biến nào mà có giá trị null thì kết quả trả về sẽ là false. Ví dụ:

public class Simple {
	public static void main(String args[]) {
		Simple s = new Simple();
		System.out.println(s instanceof Simple);// true
}
}

Một đối tượng có kiểu của lớp con thì cũng có kiểu của lớp cha.

Ví dụ: Nếu Dog kế thừa từ Animal thì đối tượng của Dog có thể tham chiếu đến cả hai lớp DogAnimal.

class Animal {}
public class Dog extends Animal {// Dog inherits Animal
	public static void main(String args[]) {
		Dog dog = new Dog();
		System.out.println(dog instanceof Animal);// true
	}
}

Nếu sử dụng toán tử instanceof với biến có kiểu bất kỳ có giá trị null thì giá trị trả về luôn là null. Ví dụ:

public class Dog {
	public static void main(String args[]) {
		Dog d = null;
		System.out.println(d instanceof Dog);// false
	}
}
5/5 - (1 bình chọn)
Bài trước và bài sau trong môn học<< Sử dụng interface trong JavaTính đóng gói (encapsulation) trong Java >>
Chia sẻ trên mạng xã hội:

Trả lời

Lưu ý:

1) Vui lòng bình luận bằng tiếng Việt có dấu.

2) Khuyến khích sử dụng tên thật và địa chỉ email chính xác.

3) Mọi bình luận trái quy định sẽ bị xóa bỏ.