Monday, September 28, 2015

[Java] Kế thừa trên Java

I KẾ THỪA ĐƠN
1 Lớp
Java coi lớp là một khuôn mẫu (Template) của một đối tượng, trong đó lớp chứa các thuộc tính và các phương thức hoạt động của đối tượng.
Khai báo lớp
Một lớp được khai báo với cú pháp:
<tính chất> class <tên lớp>
{
}
Lớp trong java có ba tính chất đặc trưng bởi ba từ khoá:
•  public: Lớp thông thường, có thể được truy cập từ các gói (package) khác. public là giá trị mặc định cho tính chất của lớp.
•  final: Khai báo lớp hằng, lớp này không thể tạo dẫn xuất. Tức là không có lớp nào kế thừa được từ các lớp có tính chất final.
•  abstract: Khai báo lớp trừu tượng, lớp này chỉ được phép chứa các phương thức trừu tượng. Hơn nữa, không thể tạo các thể hiện (Instance) của các lớp trừu tượng bằng toán tử new như các lớp thông thường.
a. Sử dụng lớp
Lớp được sử dụng khi chương trình cần một đối tượng có kiểu của lớp đó. Khi đó, đối tượng được khai báo dựa vào toán tử new:
<tên lớp> <tên đối tượng> = new <tên lớp>(); 
Ví dụ, muốn tạo một đối tượng có kiểu là lớp Person ta dùng lệnh sau:
Chương trình 1
Person myClass = new Person();  
b. Khai báo thuộc tính của lớp
Thuộc tính của lớp được khai báo theo cú pháp:
<tính chất> <kiểu dữ liệu> <tên thuộc tính>;
•  Kiểu dữ liệu: có thể là các kiểu dữ liệu cơ bản sẵn có của java, có thể là các lớp do người dùng tự định nghĩa.
•  Tên thuộc tính: được đặt tên theo quy tắc đặt tên biến của java.
•  Tính chất: Các thuộc tính và phương thức của lớp có các tính chất được đặc trưng bởi các từ khoá sau (giá trị mặc định là public):
-  public: có thể được truy cập từ bên ngoài lớp định nghĩa.
-  protected: chỉ được truy cập từ lớp định nghĩa và các lớp kế thừa từ lớp đó.
-  private: chỉ được truy cập trong phạm vi bản thân lớp định nghĩa.
-  static: được dùng chung cho một thể hiện của lớp, có thể được truy cập trực tiếp bằng . mà không cần khởi tạo một thể hiện của lớp.
-  abstract: định nghĩa một thuộc tính trừu tượng. Thuộc tính này không thể truy nhập trong lớp nhưng có thể bị định nghĩa chồng ở các lớp kế thừa.
-  final: một thuộc tính hằng, không bị định nghĩa chồng ở các lớp kế thừa.
-  native: dùng cho phương thức khi cài đặt phụ thuộc môi trường trong một ngôn ngữ khác, như C hay hợp ngữ.
-  synchronized: dùng cho phương thức tới hạn, nhằm ngăn các tác động của các đối tượng khác khi phương thức đang được thực hiện.

Minh hoạ việc khai báo hai thuộc tính là tên và tuổi của lớp Người (Person).

Chương trình 2
class Person 
{ 
public String name; 
public int  age; 
}
c. Khai báo phương thức của lớp
Phương thức của lớp được khai báo theo cú pháp
<tính chất> <kiểu trả về> <tên phương thức> ([<các tham số>])
[throws <các ngoại lệ>]
{
}
•  Tính chất: đặc trưng bởi các từ khóa tương tự như tính chất của thuộc tính. Giá trị mặc định là public.
•  Kiểu trả về: Kiểu dữ liệu trả về của phương thức, có thể là kiểu dữ liệu sẵn có của java hoặc là kiểu do người dùng tự định nghĩa.
•  Tên phương thức: tuân theo qui tắc đặt tên biến của java.
•  Các ngoại lệ: là một đối tượng đặc biệt được tạo ra khi chương trình gặp lỗi. Java sẽ trả lại cho chương trình ngoại lệ này theo từ khóa throws. Các ngoại lệ, nếu có, được phân cách nhau bởi dấu phẩy.
•  Các tham số: các tham số của phương thức, được liệt kê theo cặp <kiểu tham số> <tên tham số>, các tham số được phân biệt bởi dấu phẩy.
Chương trình mô tả việc khai báo phương thức show() để hiển thị thông tin cá nhân của lớp Person.
Chương trình 3
class Person
{
 public String name;
 public int  age;
 public void show()
 {
  System.out.println(name + “ is ” + age + “ years old!”);
 }
}
d. Phương thức khởi tạo của lớp
Phương thức khởi tạo (Constructor) được dùng để khởi tạo một thể hiện cụ thể của một lớp, nghĩa là gán các giá trị khởi đầu cho các thuộc tính, nếu có, và tạo ra một đối tượng cụ thể. Phương thức khởi tạo phải cùng tên với lớp.
Lưu ý:
•  Phương thức khởi tạo phải có tên trùng với tên của lớp
•  Phương thức khởi tạo không có giá trị trả về
•  Phương thức khởi tạo có tính chất public
•  Có thể có nhiều phương thức khởi tạo của cùng một lớp
Chương trình minh hoạ một phương thức khởi tạo của lớp Person bằng cách gán giá trị cho các thuộc tính tên và tuổi.
Chương trình 4a
class Person 
{ 
public String name; 
public int  age; 
// Phương thức khởi dựng 
public Person(String name1, int age1) 
{ 
name = name1; 
age = age1; 
} 
public void show() 
{ 
System.out.println( name + “ is ” + age + “ years old!”); 
} 
}
Chương trình sau này sẽ tạo ra một đối tượng myPerson của lớp Person với các thuộc tính có giá trị khởi tạo: name = ”Minh” và age = ”21”. Sau đó, chương trình sửdụng phương thức show() của đối tượng myPerson đểin ra dòng thông báo “Minh is 21 years old!”.
Chương trình 4b
class PersonDemo 
{ 
public static void main(String args[]) 
{ 
Person myPerson = new Person(“Minh”, 21); 
myPerson.show(); 
} 
}
e. Biến this
Biến this là một biến ẩn đặc biệt luôn tồn tại trong các lớp java: một lớp có đúng một biến ẩn this. Biến này được sử dụng trong khi chạy và nó trỏ đến bản thân lớp chứa nó. Biến this thường được sử dụng trong các hàm khởi tạo của lớp. Chương trình sau khai báo một lớp có dùng biến this trong hàm khởi tạo của lớp.
Chương trình 4c.
class Person
{
 public String name;
 public int  age;
 // Phương thức khởi dựng 
 public Person(String name, int age)
 {
  this.name = name;
  this.age = age;
 }
 public void show()
 {
  System.out.println(name + “ is ” + age + “ years old!”);
 }
}
2 Sự kế thừa
Sự kế thừa được sử dụng khi muốn tạo một lớp mới từmột lớp đã biết. Khi đó, tất cả các thuộc tính và phương thức của lớp cũ đều trở thành thuộc tính và phương thức của lớp mới. Lớp cũđược gọi là lớp cha, lớp mới được gọi là lớp con.
a. Khai báo lớp kế thừa.
Khai báo lớp kế thừa được thực hiện bởi từ khóa extends:
<thuộc tính> <tên lớp con> extends <tên lớp cha> 

{ 

}
Chương trình sau minh hoạ việc tạo một lớp Nhân viên (Employee) được kế thừa từ lớp Person đã được xây dựng.
Chương trình 5a
class Employee extends Person
{
 public float salary;
 // Phương thức khởi dựng 
 public Employee(String name, int age, float salary)
 {
  super(name, age);
  this.salary = salary;
 }
}
Khi đó, đoạn chương trình sau vẫn in ra dòng thông báo “Minh is 21 years old!” vì khi đó đối tượng myEmployee gọi đến phương thức show() được kế thừa từ lớp Person.
Chương trình 5b
class EmployeeDemo1 
{ 
public static void main(String args[]) 
{ 
Employee myEmployee = new Employee(“Minh”, 21, 300f); 
myEmployee.show(); 
} 
}
b. Khai báo phương thức nạp chồng
Khi muốn thay đổi nội dung của các phương thức được kế thừa từ lớp cha, ta dùng cách khai báo phương thức nạp chồng. Thực ra là khai báo lại một phương thức mới có cùng tên và kiểu với một phương thức đã có trong lớp cha.
Chương trình sau sẽ khai báo nạp chồng phương thức show() của lớp Employee mà không dùng lại phương thức show() của lớp Person nữa.
Chương trình 6a
class Employee extends Person
{
 public float salary;
 // Phương thức khởi dựng 
 public Employee(String name, int age, float salary)
 {
  super(name, age);
  this.salary = salary;
 }
 // Khai báo nạp chồng 
 public void show()
 {
  System.out.println(name + “has a salary of”
   + salary + “$ / month”);
 }
}
Khi đó, đoạn chương trình sau sẽ in ra dòng thông báo “Minh has a salary of 300$/month” thay
vì dòng thông báo “Minh is 21 years old!”. Lí do là lúc này, đối tượng myEmployee sẽ gọi phương thức show() của lớp Employee mà không gọi phương thức show() của lớp Person nữa.
Chương trình 6b
class EmployeeDemo2
{
 public static void main(String args[])
 {
  Employee myEmployee = new Employee(“Minh”, 21, 300f);
  myEmployee.show();
 }
}
c. Quy tắc truy nhập trong kế thừa
Các quy tắc này quy định khả năng truy nhập của lớp con đối với các thuộc tính và phương thức của lớp cha:
•  private: chỉ được truy nhập trong phạm vi lớp cha, lớp con không truy nhập được. Tất cả các lớp ngoài lớp cha đều không truy nhập được.
•  protected: lớp con có thể truy nhập được. Tất cả các lớp không kế thừa từ lớp cha đều không truy nhập được.
•  final: lớp con có thể sử dụng được nhưng không thể khai báo nạp chồng được.
•  public: lớp con có thể sử dụng và nạp chồng được. Tất cả các lớp bên ngoài đều sử dụng được.
II. KẾ THỪA BỘI
Nhằm tránh những nhập nhằng của tính chất đa kế thừa của C++, Java không cho phép kế thừa trực tiếp từ nhiều hơn một lớp cha. Nghĩa là Java không cho phép đa kế thừa trực tiếp, nhưng cho phép cài đặt nhiều giao tiếp (Interface) để có thể thừa hưởng thêm các thuộc tính và phương thức của các giao tiếp đó.
1. Giao tiếp
a. Khai báo giao tiếp
Cú pháp khai báo một giao tiếp như sau:
[public] interface <tên giao tiếp> [extends <danh sách giao tiếp>]

{

}
•  Tính chất: tính chất của một giao tiếp luôn là public. Nếu không khai báo tường minh thì giá trị mặc định cũng là public.
•  Tên giao tiếp: tuân thủ theo quy tắc đặt tên biến của java.
•  Danh sách các giao tiếp: danh sách các giao tiếp cha đã được định nghĩa để kế thừa, các giao tiếp cha được phân cách nhau bởi dấu phẩy. (Phần trong ngoặc vuông “[]” là tuỳchọn).
Lưu ý:
•  Một giao tiếp chỉcó thể kế thừa từ các giao tiếp khác mà không thể được kế thừa từ các lớp sẵn có. 
Chương trình sau minh hoạ việc khai báo một giao tiếp không kế thừa từ bất kì một giao tiếp nào.
Chương trình 7
public interface Product 
{ 
}
b. Khai báo phương thức của giao tiếp 
Cú pháp khai báo một phương thức của giao tiếp như sau:
[public] <kiểu giá trị trả về> <tên phương thức> ([<các tham số>])
[throws <danh sách ngoại lệ>];
•  Tính chất: tính chất của một thuộc tính hay phương thức của giao tiếp luôn là public. Nếu không khai báo tường minh thì giá trị mặc định cũng là public. Đối với thuộc tính, thì chất chất luôn phải thêm là hằng (final) và tĩnh (static).
•  Kiểu giá trị trả về: có thể là các kiểu cơ bản của java, cũng có thể là kiểu do người dùng tự định nghĩa (kiểu đối tượng).
•  Tên phương thức: tuân thủ theo quy tắc đặt tên phương thức của lớp
•  Các tham số: nếu có thì mỗi tham số được xác định bằng một cặp <kiểu tham số> <tên tham số>. Các tham số được phân cách nhau bởi dấu phẩy.
•  Các ngoại lệ: nếu có thì mỗi ngoại lệ được phân cách nhau bởi dấu phẩy.
Lưu ý:
•  Các phương thức của giao tiếp chỉ được khai báo dưới dạng mẫu mà không có cài đặt chi tiết (có dấu chấm phẩy ngay sau khai báo và không có phần cài đặt trong dấu “{}”). Phần cài đặt chi tiết của các phương thức chỉ được thực hiện trong các lớp (class) sử dụng giao tiếp đó.
•  Các thuộc tính của giao tiếp luôn có tính chất là hằng (final), tĩnh (static) và public. Do đó, cần gán giá trị khởi đầu ngay khi khai báo thuộc tính của giao tiếp.
Chương trình sau minh hoạ việc khai báo một thuộc tính và một phương thức của giao tiếp Product đã được khai báo trong chương trình 7: thuộc tính lưu nhãn hiệu của nhà sản xuất sản phẩm; phương thức dùng để truy xuất giá bán của sản phẩm.
Chương trình 8
public interface Product
{
 public static final String MARK = “Adidas”;
 public float getCost();
}
2 Sử dụng giao tiếp
Vì giao tiếp chỉ được khai báo dưới dạng các phương thức mẫu và các thuộc tính hằng nên việc sử dụng giao tiếp phải thông qua một lớp có cài đặt giao tiếp đó. Việc khai báo một lớp có cài đặt giao tiếp được thực hiện thông qua từ khoá implements như sau:
<tính chất> class <tên lớp> implements <các giao tiếp>
{
}
•  Tính chất và tên lớp được sử dụng như trong khai báo lớp thông thường.
•  Các giao tiếp: một lớp có thể cài đặt nhiều giao tiếp. Các giao tiếp được phân cách nhau bởi dấu phẩy. Khi đó, lớp phải cài đặt cụ thể tất cả các phương thức của tất cả các giao tiếp mà nó sử dụng.
Lưu ý:
•  Một phương thức được khai báo trong giao tiếp phải được cài đặt cụ thể trong lớp có cài đặt giao tiếp nhưng không được phép khai báo chồng. Nghĩa là số lượng các tham số của phương thức trong giao tiếp phải được giữ nguyên khi cài đặt cụ thể trong lớp. Chương trình 9 minh hoạ việc cài đặt một lớp giày (Shoe) cài đặt giao tiếp Product với các thuộc tính và phương thức đã được khai báo trong chương trình 8.
public class Shoe implements Product
Chương trình 9
public class Shoe implements Product
{// Cài đặt phương thức được khai báo trong giao tiếp 
 public float getCost()
 {
  return 10f;
 }
 // Phương thức truy nhập nhãn hiệu sản phẩm 
 public String getMark()
 {
  return MARK;
 }
 // Phương thức main 
 public static void main(String args[])
 {
  Shoe myShoe = new Shoe();
  System.out.println(“This shoe is ” + myShoe.getMark() +
   “ having a cost of $” + myShoe.getCost());
 }
}
Chương trình 9 sẽ in ra dòng: “This shoe is Adidas having a cost of $10”. Hàm getMark() sẽ trả về nhãn hiệu của sản phẩm, là thuộc tính đã được khai báo trong giao tiếp. Hàm getCost() là cài đặt riêng của lớp Shoe đối với phương thức đã được khai báo trong giao tiếp Product mà nó sửdụng, cài đặt này trả về giá trị 10 đối với lớp Shoe.
3 LỚP TRỪU TƯỢNG
Lớp trừu tượng là một dạng lớp đặc biệt, trong đó các phương thức chỉ được khai báo ở dạng khuôn mẫu (template) mà không được cài đặt chi tiết. Việc cài đặt chi tiết các phương thức chỉ được thực hiện ở các lớp con kế thừa lớp trừu tượng đó.
Lớp trừu tượng được sử dụng khi muốn định nghĩa một lớp mà không thể biết và định nghĩa ngay được các thuộc tính và phương thức của nó.
a. Khai báo
Khai báo lớp trừu tượng
Lớp trừu tượng được khái báo như cách khai báo các lớp thông thường, ngoại trừ có thêm từ khóa
abstracttrong phần tính chất:
[public] abstract class <tên lớp> 

{ 

}
•  Tính chất: mặc định là public, bắt buộc phải có từ khóa abstract để xác định đây là một
lớp trừu tượng.
•  Tên lớp: tuân thủ theo quy tắc đặt tên lớp thông thường của java.
Lưu ý:
•  Lớp trừu tượng cũng có thể kế thừa một lớp khác, nhưng lớp cha cũng phải là một lớp trừu tượng. (Khai báo kế thừa thông qua từ khoá extends như khai báo kế thừa thông thường). Chương trình 10 khai báo một lớp trừu tượng là lớp động vật (Animal) một cách chung chung.
Chương trình 10 
abstract class Animal 
{ 
}
Khai báo phương thức của lớp trừu tượng
Tất cả các thuộc tính và phương thức của lớp trừu tượng đều phải khai báo là trừu tượng. Hơn nữa, các phương thức của lớp trừu tượng chỉ được khai báo ở dạng khuôn mẫu mà không có phần khai báo chi tiết. Cú pháp khai báo phương thức của lớp trừu tượng:
[public] abstract <kiểu dữ liệu trảvề> <tên phương thức>
([<các tham số>]) [throws <các ngoại lệ>];
•  Tính chất: tính chất của một thuộc tính hay phương thức của lớp trừu tượng luôn là public. Nếu không khai báo tường minh thì giá trị mặc định cũng là public.
•  Kiểu dữ liệu trảvề: có thể là  các kiểu cơ bản của java, cũng có thể là  kiểu do người dùng tự định nghĩa (kiểu đối tượng).
•  Tên phương thức: tuân thủ theo quy tắc đặt tên phương thức của lớp
•  Các tham số: nếu có thì mỗi tham số được xác định bằng một cặp . Các tham số được phân cách nhau bởi dấu phẩy.
•  Các ngoại lệ: nếu có thì mỗi ngoại lệ được phân cách nhau bởi dấu phẩy.
Lưu ý:
•  Tính chất của phương thức trừu tượng không được là private hay static. Vì phương thức trừu tượng chỉ được khai báo chi tiết (nạp chồng) trong các lớp dẫn xuất (lớp kế thừa) của lớp trừu tượng. Do đó, nếu phương thức là private thì không thể nạp chồng, nếu phương thức là static thì không thể thay đổi trong lớp dẫn xuất.
•  Phương thức trừu tượng chỉ được khai báo dưới dạng khuôn mẫu nên không có phần dấu móc “{}” mà kết thúc bằng dấu chấm phẩy “;”.
Chương trình 11 khái báo hai phương thức của lớp trừu tượng Animal trong chương trình 10: Phương thức getName() trả về tên loài động vật, dù chưa biết tên cụ thể loài nào nhưng kiểu trả vềlà String. Phương thức getFeet() trả về số chân của loài động vật, cũng chưa biết cụ thể là  bao nhiêu chân nhưng kiểu trả về là int

Chương trình 11
abstract class Animal
{
 abstract String getName();
 abstract int getFeet();
}
2 Sử dụng lớp trừu tượng
Lớp trừu tượng được sử dụng thông qua các lớp dẫn xuất của nó. Vì chỉ có các lớp dẫn xuất mới cài đặt cụ thể các phương thức được khai báo trong lớp trừu tượng.
Chương trình 12a khai báo lớp về loài chim (Bird) kế thừa từ lớp Animal trong chương trình 11. Lớp này cài đặt chi tiết hai phương thức đã được khai báo trong lớp Animal: phương thức getName() sẽ trả về tên loài là “Bird”; phương thức getFeet() trả về số chân của loài chim là 2.
Chương trình 12a
public class Bird extends Animal
{
 // Trảvềtên loài chim 
 public String getName()
 {
  return “Bird”;
 }
 // Trảvềsốchân của loài chim 
 public int getFeet()
 {
  return 2;
 }
}
Chương trình 12b khai báo lớp về loài mèo (Cat) cũng kế thừa từ lớp Animal trong chương trình 11. Lớp này cài đặt chi tiết hai phương thức đã được khai báo trong lớp Animal: phương thức getName() sẽ trả về tên loài là “Cat”; phương thức getFeet() trả về số chân của loài mèo là 4.>
Chương trình 12b
public class Cat extends Animal
{
 // Trảvềtên loài mèo 
 public String getName()
 {
  return “Cat”;
 }
 // Trảvềsốchân của loài mèo 
 public int getFeet()
 {
  return 4;
 }
}
Chương trình 12c sử dụng lại hai lớp Bird và Cat trong các chương trình 12a và 12b.
Chương trình này sẽ hiển thị hai dòng thông báo:
The Bird has 2 feets
The Cat has 4 feets
Chương trình 12c
public class AnimalDemo
{
 public static void main(String args[])
 {
  Bird myBird = new Bird();
  System.out.println(“The ” + myBird.getName() + “ has ” + myBird.getFeet() + “ feets”);
  Cat myCat = new Cat();
  System.out.println(“The ” + myCat.getName() + “ has ” + myCat.getFeet() + “ feets”);
 }
}

Cám ơn bạn đã đọc bài viết này. Hãy chia sẻ bài viết và bình luận ý kiến của bạn ở bên dưới.

Share this

Chào mừng bạn đến với SimpleCodeCJava Blog - Mục đích của chúng tôi khi thành lập blog này là muốn chia sẻ những kiến thức và kinh nghiệm lập trình mà chúng tôi đã học được với mong muốn giúp đỡ mọi người, giúp bạn rút ngắn được thời gian tìm hiểu cũng như việc giải quyết những vấn đề trong lập trình C và Java.

0 Comment to "[Java] Kế thừa trên Java"