TỔNG QUAN
CẤU TRÚC ĐIỀU KHIỂN
VÒNG LẶP
CHUỖI VÀ MẢNG
COLLECTIONS
THƯ VIỆN QUAN TRỌNG
HƯỚNG ĐỐI TƯỢNG
XỬ LÝ LUỒNG
EXCEPTION
LÀM VIỆC VỚI FILE
THAM KHẢO
CÁC CHỦ ĐỀ
BÀI MỚI NHẤT
MỚI CẬP NHẬT

Tính kế thừa (Inheritance) trong Java

Trong bài trước, tôi đã giới thiệu đến các bạn tính đóng gói của lập trình hướng đối tượng trong Java. Sang bài này, tôi sẽ giới thiệu đến các bạn tính chất cơ bản tiếp theo đó là tính kế thừa (Inheritance) và cách vận dụng tính chất này trong lập trình. Cuối bài này, tôi sẽ đưa ra một số bài tập cho các bạn luyện tập!

1. Khái niệm tính kế thừa

Khái niệm tổng quát hóa và đặc biệt hóa

Quan hệ tổng quát hóa và đặc biệt hóa là 1 quan hệ thực sự rất tự nhiên và thông dụng trong thế giới thực. Đối tượng đặc biệt hóa của một dạng đối tượng tổng quát sẽ có đầy đủ tính chất của loại đối tượng ban đầu và có thêm các đặc điểm riêng của nó. Ví dụ hình chữ nhật lại là khái niệm tổng quát hóa của hình vuông, và ngược lại hình vuông là một trường hợp đặc biệt của hình chữ nhật. Hình vuông có đầy đủ các tính chất của hình chữ nhật bởi vì hình chữ nhật là tổng quát của hình vuông; hơn nữa, hình vuông có những tính chất đặc biệt mà hình chữ nhật không có bởi vì hình vuông được đặc biệt hóa từ hình chữ nhật.

banquyen png
Bài viết này được đăng tại freetuts.net, không được copy dưới mọi hình thức.

Rất nhiều lớp đối tượng trong thế giới thực là đặc biệt hóa hay tổng quát hóa của lớp đối tượng khác. Quan hệ tổng quát hóa và đặc biệt hóa đóng vai trò rất quan trọng, hầu hết các ngôn ngữ lập trình hướng đối tượng đều hỗ trợ người lập trình cài đặt quan hệ này.

Khái niệm tính kế thừa

Khái niệm "kế thừa" thường được dùng trong các ngôn ngữ lập trình hướng đối tượng để chuyển quan hệ tổng quát hóa và đặc biệt hóa của thế giới thực vào các chương trình máy tính. Tính kế thừa cho phép ta xây dựng một lớp mới dựa trên các định nghĩa của một lớp đã có.

Nếu một lớp A là lớp đặc biệt hóa của lớp B (nghĩa là lớp B là lớp tổng quát hóa của lớp A) thì trong lập trình hướng đối tượng lớp A được cài đặt là lớp kế thừa của lớp B (nói ngắn gọn là "lớp A kế thừa lớp B"). Khi lớp A kế thừa lớp B thì lớp B được gọi là "lớp cơ sở" hay "lớp cha" (trong mối quan hệ kế thừa đang xét), còn lớp A thì được gọi là "lớp kế thừa", "lớp con" hay "lớp dẫn xuất".

Lợi ích của tính kế thừa

Sau đây là một số lợi ích có được khi vận dụng tính kế thừa trong lập trình:

  • Lớp con (lớp A) có thể tận dụng lại các thuộc tính và phương thức của lớp cha (lớp B) (nghĩa là các thuộc tính và phương thức của lớp B có thể được tái sử dụng bởi lớp A).
  • Lớp A có thể định nghĩa thêm thuộc tính và phương thức mới của riêng nó và có thể định nghĩa lại (hay còn gọi là ghi đè phương thức, overriding) phương thức được kế thừa từ lớp B cho phù hợp với mục đích của nó.

Các dạng kế thừa

Trong Java, chúng ta có 3 dạng kế thừa chính đó là: kế thừa từ Class, kế thừa từ lớp trừu tượng (Abstract class) và kế thừa từ Interface. Trong phạm vi của bài này, chúng ta sẽ chỉ tìm hiểu về dạng kế thừa từ Class. Sang các bài sau, tôi sẽ trình bày về 2 dạng kế thừa còn lại.

2. Xây dựng lớp con và lớp cha trong tính kế thừa

Khi lập trình với tính kế thừa trong Java, việc đầu tiên và quan trọng nhất đó là chúng ta phải xây dựng được lớp con và lớp cha dựa vào những thông tin đã có. Vậy để làm được việc này, chúng ta sẽ làm như sau:

Xây dựng lớp cha: những thông tin nào chung giữa các đối tượng (bao gồm thuộc tính và phương thức) thì chúng ta tập hợp lại tạo thành lớp cha.

Xây dựng lớp con: những thông tin nào chỉ có trong từng đối tượng cụ thể thì chúng ta tập hợp lại tạo thành lớp con.

2. Ví dụ về tính kế thừa

Để cài đặt tính kế thừa, chúng ta sẽ sử dụng từ khóa extends. Giả sử chúng ta có 1 lóp A kế thừa từ lớp B thì chúng ta sẽ khai báo lớp B theo cú pháp như sau:

Cú pháp
public class A {
	...
}


public class B extends A {
	...
}

Để hiểu hơn về tính kế thừa, các bạn theo dõi ví dụ sau:

Calculate.java
package vidu;

public class Calculation {
	protected int c;
	public void phepCong(int a, int b) {
		c = a + b;
		System.out.println("Tổng hai số = " + c);
	}
	
	public void phepTru(int a, int b) {
		c = a - b;
		System.out.println("Hiệu hai số = " + c);
	}
}

MyCalculation.java
package vidu;

public class MyCalculation extends Calculation {
	public void phepNhan(int a, int b) {
		c = a * b;
		System.out.println("Tích 2 số = " + c);
	}
	
	public void phepLuyThua(int a, int b) {
		c = (int) Math.pow(a, b);
		System.out.println(a + "^" + b + " = " + c);
	}
	
	public static void main(String[] args) {
		int a = 12, b = 2;
		MyCalculation myCalculation = new MyCalculation();
		myCalculation.phepCong(a, b);
		myCalculation.phepTru(a, b);
		myCalculation.phepNhan(a, b);
		myCalculation.phepLuyThua(a, b);	
	}
}

Kết quả sau khi biên dịch chương trình:

ketqua vi du tinh ke thua PNG

Trong ví dụ này, tôi tạo ra 2 lớp CalculationMyCalculation kế thừa từ lớp Calculation. Trong lớp Calculation tôi có khai báo 1 thuộc tính c có kiểu int và phạm vi truy cập là protected nhằm mục đích cho phép các lớp con của lớp này có thể dùng lại thuộc tính c (các bạn có thể dùng từ khóa public hoặc không dùng từ khóa nhưng không được khai báo là private) cùng với 2 phương thức là phepCong(int a, int b) để thực hiện phép cộng và phepTru(int a, int b) để thực hiện phép trừ.

Lớp MyCalculation là lớp kế thừa từ lớp Calculation. Lớp này dùng lại thuộc tính c và 2 phương thức phepCong(int a, int b)phepTru(int a, int b) của lớp Calculation, vì vậy trong lớp MyCalculation không khai báo lại c, phepCong(int a, int b)phepTru(int a, int b) vì tất cả chúng đều được lấy lại của lớp Calculation. Ngoài ra, lớp MyCalculation còn khai báo 2 phương thức riêng của nó đó là phepNhan(int a, inb b) phepLuyThua(int a, int b) để thực hiện phép nhân và phép lũy thừa hai số.

Hàm main() của lớp MyCalculation minh họa việc khai báo và sử dụng đối tượng myCalculation (kiểu MyCalculation). Trong hàm này, tôi có 2 dòng code myCalculation.phepCong(a, b);myCalculation.phepTru(a, b); dùng để gọi phương thức phepCong(int a, int b)phepTru(int a, int b), mã nguồn của 2 phương thức này được kế thừa từ lớp Calculation mà không cần viết lại cho lớp MyCalculation.

Lưu ý:

  • Qua ví dụ trên, chúng ta có thể rút ra kết luận là một lớp con có thể kế thừa tất cả các thành phần của lớp cha (thuộc tính, phương thức,...) nhưng không thể kế thừa được lớp con. Tuy nhiên, hàm tạo của lớp cha có thể được gọi từ lớp con thông qua từ khóa super.
  • Một lớp con chỉ có thể kế thừa trực tiếp từ một lớp cha. Nếu lớp con không kế thừa từ một lớp cha nào thì mặc định nó sẽ kế thừa từ một lớp cha tên là Object.

3. Từ khóa super

Từ khóa super được sử dụng trong các trường hợp sau:

  • Nó được sử dụng để phân biệt các thành phần có cùng tên giữa lớp cha và lớp con.
  • Nó được sử dụng để gọi hàm tạo của lớp cha từ lớp con.

Phân biệt các thành phần có cùng tên giữa lớp cha và lớp con.

Nếu chúng ta có một lớp con thừa kế từ một lớp cha và các thành phần của lớp cha có cùng tên với các thành phần của lớp con thì để phân biệt các thành phần của lớp cha từ lớp con, chúng ta sẽ sử dụng từ khóa super với cú pháp như sau:

Cú pháp
super.tên_thuộc_tính;
super.tên_phương_thức();

Dưới đây là ví dụ minh họa cách sử dụng từ khóa super trong trường hợp này.

Superclass.java
package vidu;

public class Superclass {
	int number = 10;

	public void hienThi() {
		System.out.println("Đây là phương thức hienThi() của lớp cha");
	}
}

Subclass.java
package vidu;

public class Subclass extends Superclass {
	int number = 20;

	public void hienThi() {
		System.out.println("Đây là phương thức hienThi() của lớp con");
	}
	
	public void subclassMethod() {
		Subclass subclass = new Subclass();
		
		// gọi phương thức hienThi() của lớp cha
		// sử dụng từ khóa super()
		super.hienThi();
		
		// gọi phương thức hienThi() của lớp con
		subclass.hienThi();
		
		// hiển thị giá trị biến number của lớp cha
		System.out.println("Giá trị biến number của lớp cha = " + super.number);
		
		// hiển thị giá trị biến number của lớp con
		System.out.println("Giá trị biến number của lớp con = " + subclass.number);
	}


	public static void main(String[] args) {
		Subclass objSubclass = new Subclass();
		objSubclass.subclassMethod();
	}

}

Kết quả sau khi biên dịch chương trình:

ketqua vi du tu khoa super 1 PNG

Giải thích hoạt động của chương trình trên.

Trong ví dụ này chúng ta có 2 lớp: lớp cha tên là Superclass và lớp con tên là Subclass. Hai lớp này cùng có một phương thức tên là hienThi() với nội dung phương thức khác nhau và cùng có một biến number với giá trị biến khác nhau. Trong lớp Subclass chúng ta sẽ tiến hành gọi đến phương thức hienThi() và thuộc tính number của 2 lớp này. Đối với thuộc tính và phương thức của lớp Superclass, chúng ta sẽ gọi thông qua từ khóa super với 2 dòng code là super.hienThi()super.number, còn đối với thuộc tính và phương thức của lớp Subclass thì chúng ta gọi bình thường thông qua tên đối tượng của nó.

Gọi hàm tạo của lớp cha

Nếu chúng ta có 1 lớp là lớp con của một lớp khác thì lớp con đó có thể tự động gọi được hàm tạo mặc định của lớp cha. Nhưng trong trường hợp chúng ta muốn gọi hàm tạo có đối số của lớp cha, chúng ta cần sử dụng từ khóa super với cú pháp như sau:

Cú pháp
super(tên_đối_số);

Lưu ý: từ khóa super trong trường hợp này chỉ có thể được dùng ngay trong hàm tạo và phải được khai báo đầu tiên bên trong hàm tạo đó, nếu chúng ta để nó vào trong các phương thức bình thường khác thì hệ thống sẽ báo lỗi.

Dưới đây là ví dụ minh họa cách sử dụng từ khóa super trong trường hợp này.

Superclass.java
package vidu;

public class Superclass {
	
	public Superclass(int number) {
		System.out.println("Đây là hàm tạo có đối số của lớp Superclass, giá trị"
				+ " biến number = " + number);
	}
}

Subclass.java
package vidu;

public class Subclass extends Superclass {

	public Subclass(int number) {
		super(number);	// gọi hàm tạo của lớp Superclass
		System.out.println("Đây là hàm tạo của lớp Subclass, giá trị biến number = " + number);
	}

	public static void main(String[] args) {
		Subclass subclass = new Subclass(10);
	}

}

Kết quả sau khi biên dịch chương trình:

ketqua vi du tu khoa super 2 PNG

3. Lời kết

Trong bài này, chúng ta đã tìm hiểu về tính kế thừa trong Java. Sang bài sau, chúng ta sẽ tìm hiểu về tính chất tiếp theo trong lập trình hướng đối tượng đó là tính đa hình. Các bạn theo dõi nhé!

Câu hỏi thường gặp liên quan:

Cùng chuyên mục:

Khi nào dùng Default Methods trong Java 8

Khi nào dùng Default Methods trong Java 8

Ở 2 bài trước chúng ta đã tìm hiểu 2 tính năng mới của Java…

Cách chuyển chữ hoa thành chữ thường trong Java

Cách chuyển chữ hoa thành chữ thường trong Java

Trong bài viết này chúng ta sẽ tìm hiểu về cách chuyển đổi chữ in…

Bài tập tính tổng các số tự nhiên trong Java

Bài tập tính tổng các số tự nhiên trong Java

Các số dương 1, 2, 3, 4, ... được gọi là các số tự nhiên,…

Cách chuyển chữ thường thành chữ hoa trong Java

Cách chuyển chữ thường thành chữ hoa trong Java

Trong chuỗi có thể vừa có ký tự thường vừa có ký tự hoa, nhưng…

Cách viết hoa ký tự đầu tiên trong Java

Cách viết hoa ký tự đầu tiên trong Java

Để hiểu được bài này, các bạn cần có kiến thức căn bản về Java…

Hướng dẫn chuyển đổi giờ phút giây trong Java

Hướng dẫn chuyển đổi giờ phút giây trong Java

Để hiểu được chương trình, các bạn cần có kiến thức cơ bản về Java.…

Cách lấy thời gian hiện tại trong Java

Cách lấy thời gian hiện tại trong Java

Để hiểu được bài viết này, các bạn cần có kiến thức cơ bản sau…

Cách làm tròn số trong Java

Cách làm tròn số trong Java

Khi thực hiện tính toán, việc kết quả ra một con số thập phân dài…

Cách tìm ma trận chuyển vị trong Java

Cách tìm ma trận chuyển vị trong Java

Quá trình hoán đổi giữa hàng và cột được gọi là chuyển vị của ma…

Cách chuyển ArrayList thành mảng và ngược lại trong Java

Cách chuyển ArrayList thành mảng và ngược lại trong Java

Để hiểu được bài này, các bạn cần có kiến thức cơ bản về mảng…

Cách nối hai mảng trong Java

Cách nối hai mảng trong Java

Mình sẽ thực hiện hai chương trình nối mảng. Chương trình thứ nhất nối hai…

Cách xóa khoảng trắng của chuỗi trong Java

Cách xóa khoảng trắng của chuỗi trong Java

Mình sẽ thực hiện hai chương trình khác nhau để các bạn có thể hiểu…

In ra tam giác bằng ký tự * và số trong Java

In ra tam giác bằng ký tự * và số trong Java

Mình sẽ giới thiệu cách để in ra các tam giác bằng ký tự *…

Tìm số lớn nhất trong mảng Java

Tìm số lớn nhất trong mảng Java

Các bạn cần tìm hiểu về mảng, cách khởi tạo và in mảng trong Java…

Tìm ước của một số nguyên trong Java

Tìm ước của một số nguyên trong Java

Trong bài viết này chúng ta sẽ tìm hiểu cách tìm tất cả các ước…

Cách kiểm tra số hoàn hảo trong Java

Cách kiểm tra số hoàn hảo trong Java

Cách kiểm tra số đối xứng trong Java

Cách kiểm tra số đối xứng trong Java

Trong bài viết này chúng ta sẽ kiểm tra một số có phải là số…

Đảo ngược một số trong Java

Đảo ngược một số trong Java

Mình sẽ giới thiệu các bạn cách đảo ngược một số sử dụng vòng lặp…

Tìm bội chung nhỏ nhất trong Java

Tìm bội chung nhỏ nhất trong Java

Mình sẽ sử dụng hai cách khác nhau để tìm BCNN. Cách thứ nhất mình…

Cách hoán đổi hai số trong Java

Cách hoán đổi hai số trong Java

Trong phần này mình sẽ sử dụng một biến tạm temp() làm biến trung gian…

Top