Thừa kế và đa hình trong Java
1. Giới thiệu
Thừa kế và đa hình (Inheritance & polymorphism) - đây là một khái niệm vô cùng quan trọng trong Java. Mà bạn bắt buộc phải hiểu nó.
2. Class, cấu tử và đối tượng (Class, Constructor, instance)
Bạn cần hiểu một cách rạch ròi về class, cấu tử (constructor) và đối tượng trước khi bắt đầu tìm hiểu quan hệ thừa kế trong java. Chúng ta xem class Person, mô tả một con người với các thông tin tên, năm sinh, nơi sinh.
Person.java
package org.o7planning.tutorial.inheritance.basic;
public class Person {
// Trường name - Thông tin tên người.
private String name;
// Trường bornYear - thông tin năm sinh
private Integer bornYear;
// Trường placeOfBirth - thông tin nơi sinh.
private String placeOfBirth;
// Constructor có 3 tham số.
// Mục đích nhằm để gán các giá trị cho các trường của Person.
// Chỉ định rõ tên, năm sinh, nơi sinh của một người.
public Person(String name, Integer bornYear, String placeOfBirth) {
this.name = name;
this.bornYear = bornYear;
this.placeOfBirth = placeOfBirth;
}
// Constructor có 2 tham số.
// Mục đích gán các giá trị cho 2 trường tên và năm sinh cho Person.
// Nơi sinh không được gán.
public Person(String name, Integer bornYear) {
this.name = name;
this.bornYear = bornYear;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getBornYear() {
return bornYear;
}
public void setBornYear(Integer bornYear) {
this.bornYear = bornYear;
}
public String getPlaceOfBirth() {
return placeOfBirth;
}
public void setPlaceOfBirth(String placeOfBirth) {
this.placeOfBirth = placeOfBirth;
}
}
PersonDemo.java
package org.o7planning.tutorial.inheritance.basic;
public class PersonDemo {
public static void main(String[] args) {
// Đối tượng: Thomas Edison.
Person edison = new Person("Thomas Edison", 1847);
System.out.println("Info:");
System.out.println("Name: " + edison.getName());
System.out.println("Born Year: " + edison.getBornYear());
System.out.println("Place Of Birth: " + edison.getPlaceOfBirth() );
// Đối tượng: Bill Gates
Person billGates = new Person("Bill Gate", 1955, "Seattle, Washington");
System.out.println("Info:");
System.out.println("Name: " + billGates.getName());
System.out.println("Born Year: " + billGates.getBornYear());
System.out.println("Place Of Birth: " + billGates.getPlaceOfBirth());
}
}
Phân biệt Class, cấu tử (constructor) và đối tượng:
Lớp Person mô phỏng một lớp người, nó là một thứ gì đó trừu tượng, nhưng nó có các trường để mang thông tin, trong ví dụ trên là tên, năm sinh, nơi sinh.
Cấu tử (Constructor) - Người ta còn gọi là "Phương thức khởi tạo"
Cấu tử (Constructor) - Người ta còn gọi là "Phương thức khởi tạo"
- Cấu tử luôn có tên giống tên lớp.
- Một class có một hoặc nhiều cấu tử.
- Cấu tử có hoặc không có tham số, cấu tử không có tham số còn gọi là cấu tử mặc định.
- Cấu tử được sử dụng để tạo ra một đối tượng của lớp.
Như vậy lớp Person (Mô tả lớp người) là thứ trừu tượng, nhưng khi chỉ rõ vào bạn hoặc tôi thì đó là 2 đối tượng (instance) thuộc lớp Person. Và Constructor là phương thức đặc biệt để tạo ra đối tượng, Constructor sẽ gán các giá trị vào các trường (field) của class cho đối tượng..
Hãy xem minh họa, khởi tạo đối tượng từ cấu tử như thế nào.
3. Thừa kế trong java
Chúng ta cần một vài class tham gia vào minh họa.
- Animal: Class mô phỏng một lớp Động vật.
- Duck: Class mô phỏng lớp vịt, là một class con của Animal.
- Cat: Class mô phỏng lớp mèo, là một class con của Animal
- Mouse: Class mô phỏng lớp chuột, là một class con của Animal.
Ở đây chúng ta có class Animal, với một method không có nội dung.
Class Animal có 1 phương thức trừu tượng nó phải được khai báo là trìu tượng (abstract). Class trừu tượng có các cấu tử (constructor) nhưng bạn không thể khởi tạo đối tượng từ nó.
- public abstract String getAnimalName();
Class Animal có 1 phương thức trừu tượng nó phải được khai báo là trìu tượng (abstract). Class trừu tượng có các cấu tử (constructor) nhưng bạn không thể khởi tạo đối tượng từ nó.
- Về bản chất nghĩa là bạn muốn tạo một đối tượng động vật, bạn cần tạo từ một loại đông vật cụ thể, trong trường hợp này bạn phải khởi tạo từ cấu tử (constructor) của Cat, Mouse hoặc Duck.
Animal.java
package org.o7planning.tutorial.inheritance.animal;
// Lớp có ít nhất 1 phương thức trừu tượng
// bắt buộc phải được khai báo là trừu tượng.
public abstract class Animal {
// Tên, ví dụ Mèo Tom, Chuột Jerry.
private String name;
// Constructor mặc định.
public Animal() {
// Gán giá trị mặc định cho 'name'.
this.name = this.getAnimalName();
}
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// Đây là một phương thức trừu tượng.
// Trả về tên của loài động vật này.
// Nội dung cụ thể của phương thức này
// sẽ được thực hiện (implemented) tại các lớp con.
public abstract String getAnimalName();
}
Tiếp theo xem class Cat, thừa kế từ Animal.
Cat cũng có các cấu tử của nó, và cũng có các trường của nó. Trong dòng đầu tiên của cấu tử bao giờ cũng phải gọi super(..) nghĩa là gọi lên cấu tử cha, để khởi tạo giá trị cho các trường của class cha.
Nếu bạn không gọi, mặc định Java hiểu là đã gọi super(), nghĩa là gọi cấu tử mặc định của class cha.
Nếu bạn không gọi, mặc định Java hiểu là đã gọi super(), nghĩa là gọi cấu tử mặc định của class cha.
Cat.java
package org.o7planning.tutorial.inheritance.animal;
public class Cat extends Animal {
private int age;
private int height;
public Cat(int age, int height) {
// Gọi tới Constructor mặc định của lớp cha (Animal).
// Nhằm mục đích gán tạo giá trị cho các trường (field) của lớp cha.
super();
// Sau đó mới gán giá trị cho các trường (field) của nó.
this.age = age;
this.height = height;
}
public Cat(String name, int age, int height) {
// Gọi tới Constructor của lớp cha (Animal)
// Nhằm mục đích gán tạo giá trị cho các trường (field) của lớp cha.
super(name);
// Sau đó mới gán giá trị cho các trường (field) của nó.
this.age = age;
this.height = height;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
// Thực hiện (implement) phương thức trừu tượng được khai báo tại lớp cha.
@Override
public String getAnimalName() {
return "Cat";
}
}
Khi bạn khởi tạo một đối tượng Cat điều gì xẩy ra?
Xem class Mouse, thừa kế từ Animal.
Mouse.java
package org.o7planning.tutorial.inheritance.animal;
public class Mouse extends Animal {
private int weight;
// Constructor mặc định.
public Mouse() {
// Gọi tới cấu tử Mouse(int)
// Call to constructor Mouse(int)
this(100);
}
// Constructor có 1 tham số
public Mouse(int weight) {
// Nếu bạn không gọi bất kỳ một super(..) nào.
// Java sẽ gọi một super() mặc định.
// super();
this.weight = weight;
}
// Constructor có 2 tham số.
public Mouse(String name, int weight) {
super(name);
this.weight = weight;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public String getAnimalName() {
return "Mouse";
}
}
InstanceofDemo.java
package org.o7planning.tutorial.inheritance.demo;
import org.o7planning.tutorial.inheritance.animal.Animal;
import org.o7planning.tutorial.inheritance.animal.Cat;
import org.o7planning.tutorial.inheritance.animal.Mouse;
public class InstanceofDemo {
public static void main(String[] args) {
// Khởi tạo một đối tượng động vật.
// Animal là một lớp trừu tượng,
// bạn không thể tạo ra một đối tượng từ Constructor của Animal.
Animal tom = new Cat("Tom", 3, 20);
System.out.println("name: " + tom.getName());
System.out.println("animalName: " + tom.getAnimalName());
// Sử dụng toán tử 'instanceof' để kiểm tra xem
// một đối tượng có phải là một kiểu nào đó hay không.
boolean isMouse = tom instanceof Mouse;
System.out.println("Tom is mouse? " + isMouse);
boolean isCat = tom instanceof Cat;
System.out.println("Tom is cat? " + isCat);
boolean isAnimal = tom instanceof Animal;
System.out.println("Tom is animal? " + isAnimal);
}
}
Kết quả chạy ví dụ:
name: Tom
animalName: Cat
Tom is mouse? false
Tom is cat? true
Tom is animal? true
InheritMethodDemo.java
package org.o7planning.tutorial.inheritance.demo;
import org.o7planning.tutorial.inheritance.animal.Cat;
public class InheritMethodDemo {
public static void main(String[] args) {
// Tạo một đối tượng Cat.
Cat tom = new Cat("Tom", 3, 20);
// Gọi các phương thức thừa kế được từ lớp cha (Animal).
System.out.println("name: " + tom.getName());
System.out.println("animalName: " + tom.getAnimalName());
System.out.println("-----------------");
// Gọi các phương thức được khai báo trên lớp Cat.
System.out.println("Age: " + tom.getAge());
System.out.println("Height: " + tom.getHeight());
}
}
Kết quả chạy ví dụ:
name: Tom
animalName: Cat
-----------------
Age: 3
Height: 20
Ép kiểu (Cast) trong Java
CastDemo.java
package org.o7planning.tutorial.inheritance.demo;
import java.util.Random;
import org.o7planning.tutorial.inheritance.animal.Animal;
import org.o7planning.tutorial.inheritance.animal.Cat;
import org.o7planning.tutorial.inheritance.animal.Mouse;
public class CastDemo {
// Phương thức này trả về ngẫu nhiên một con vật.
public static Animal getRandomAnimal() {
// Trả về giá trị ngẫu nhiên 0 hoặc 1.
int random = new Random().nextInt(2);
Animal animal = null;
if (random == 0) {
animal = new Cat("Tom", 3, 20);
} else {
animal = new Mouse("Jerry", 5);
}
return animal;
}
public static void main(String[] args) {
Animal animal = getRandomAnimal();
if (animal instanceof Cat) {
// Ép kiểu (cast) thành kiểu Cat.
Cat cat = (Cat) animal;
// Và gọi một phương thức của lớp Cat.
System.out.println("Cat height: " + cat.getHeight());
} else if (animal instanceof Mouse) {
// Ép kiểu (cast) thành kiểu Mouse.
Mouse mouse = (Mouse) animal;
// Và gọi một phương thức của lớp Mouse.
System.out.println("Mouse weight: " + mouse.getWeight());
}
}
}
4. Tính đa hình trong Java
Bạn có một con mèo nguồn gốc châu Á (AsianCat), bạn có thể nói nó là một con mèo (Cat) hoặc nói nó là một con vật (Animal) đó là một khía cạnh của từ đa hình.
Hoặc một ví dụ khác: Trên lý lịch của bạn ghi rằng bạn là một người châu Á, trong khi đó bạn thực tế là một người Việt Nam.
Ví dụ dưới đây cho bạn thấy cách hành sử giữa khai báo và thực tế
Hoặc một ví dụ khác: Trên lý lịch của bạn ghi rằng bạn là một người châu Á, trong khi đó bạn thực tế là một người Việt Nam.
Ví dụ dưới đây cho bạn thấy cách hành sử giữa khai báo và thực tế
Class AsianCat là một class thừa kế từ Cat.
AsianCat.java
package org.o7planning.tutorial.inheritance.animal;
public class AsianCat extends Cat {
public AsianCat(String name, int age, int height) {
super(name, age, height);
}
// Ghi đè (override) phương thức của lớp cha (Cat)
@Override
public String getAnimalName() {
return "Asian Cat";
}
}
Tính đa hình của Java được giải thích trong hình minh họa dưới đây:
PolymorphismDemo.java
package org.o7planning.tutorial.polymorphism;
import org.o7planning.tutorial.inheritance.animal.AsianCat;
import org.o7planning.tutorial.inheritance.animal.Cat;
public class PolymorphismDemo {
public static void main(String[] args) {
Cat cat1 = new Cat("Tom", 3, 20);
Cat cat2 = new AsianCat("ATom", 2, 19);
System.out.println("Animal Name of cat1: " + cat1.getAnimalName());
System.out.println("Animal Name of cat2: " + cat2.getAnimalName());
}
}
Kết quả chạy ví dụ:
Animal Name of cat1: Cat
Animal Name of cat2: Asian Cat
Java cơ bản
- Tùy biến trình biên dịch java xử lý Annotation của bạn (Annotation Processing Tool)
- Lập trình Java theo nhóm sử dụng Eclipse và SVN
- Hướng dẫn và ví dụ Java WeakReference
- Hướng dẫn và ví dụ Java PhantomReference
- Hướng dẫn nén và giải nén trong Java
- Cấu hình Eclipse để sử dụng JDK thay vì JRE
- Phương thức String.format() và printf() trong Java
- Cú pháp và các tính năng mới trong Java 5
- Cú pháp và các tính năng mới trong Java 8
- Hướng dẫn sử dụng biểu thức chính quy trong Java
- Hướng dẫn lập trình đa luồng trong Java - Java Multithreading
- Thư viện điều khiển các loại cơ sở dữ liệu khác nhau trong Java
- Hướng dẫn sử dụng Java JDBC kết nối cơ sở dữ liệu
- Lấy các giá trị của các cột tự động tăng khi Insert một bản ghi sử dụng JDBC
- Hướng dẫn và ví dụ Java Stream
- Functional Interface trong Java
- Giới thiệu về Raspberry Pi
- Hướng dẫn và ví dụ Java Predicate
- Abstract class và Interface trong Java
- Access modifier trong Java
- Hướng dẫn và ví dụ Java Enum
- Hướng dẫn và ví dụ Java Annotation
- So sánh và sắp xếp trong Java
- Hướng dẫn và ví dụ Java String, StringBuffer và StringBuilder
- Hướng dẫn xử lý ngoại lệ trong Java - Java Exception Handling
- Hướng dẫn và ví dụ Java Generics
- Thao tác với tập tin và thư mục trong Java
- Hướng dẫn và ví dụ Java BiPredicate
- Hướng dẫn và ví dụ Java Consumer
- Hướng dẫn và ví dụ Java BiConsumer
- Bắt đầu với Java cần những gì?
- Lịch sử của Java và sự khác biệt giữa Oracle JDK và OpenJDK
- Cài đặt Java trên Windows
- Cài đặt Java trên Ubuntu
- Cài đặt OpenJDK trên Ubuntu
- Cài đặt Eclipse
- Cài đặt Eclipse trên Ubuntu
- Học nhanh Java cho người mới bắt đầu
- Lịch sử của bit và byte trong khoa học máy tính
- Các kiểu dữ liệu trong Java
- Các toán tử Bitwise
- Câu lệnh rẽ nhánh (if else) trong Java
- Câu lệnh rẽ nhánh switch trong Java
- Vòng lặp trong Java
- Mảng (Array) trong Java
- JDK Javadoc định dạng CHM
- Thừa kế và đa hình trong Java
- Hướng dẫn và ví dụ Java Function
- Hướng dẫn và ví dụ Java BiFunction
- Ví dụ về Java encoding và decoding sử dụng Apache Base64
- Hướng dẫn và ví dụ Java Reflection
- Hướng dẫn gọi phương thức từ xa với Java RMI
- Hướng dẫn lập trình Java Socket
- Các nền tảng nào bạn nên chọn để lập trình ứng dụng Java Desktop?
- Hướng dẫn và ví dụ Java Commons IO
- Hướng dẫn và ví dụ Java Commons Email
- Hướng dẫn và ví dụ Java Commons Logging
- Tìm hiểu về Java System.identityHashCode, Object.hashCode và Object.equals
- Hướng dẫn và ví dụ Java SoftReference
- Hướng dẫn và ví dụ Java Supplier
- Lập trình Java hướng khía cạnh với AspectJ (AOP)
Show More
- Hướng dẫn lập trình Java Servlet/JSP
- Các hướng dẫn Java Collections Framework
- Java API cho HTML & XML
- Các hướng dẫn Java IO
- Các hướng dẫn Java Date Time
- Các hướng dẫn Spring Boot
- Các hướng dẫn Maven
- Các hướng dẫn Gradle
- Các hướng dẫn Java Web Services
- Các hướng dẫn lập trình Java SWT
- Các hướng dẫn lập trình JavaFX
- Các hướng dẫn Java Oracle ADF
- Các hướng dẫn Struts2 Framework
- Các hướng dẫn Spring Cloud