Các bài tập về lập trình hướng đối tượng java năm 2024

Bây giờ mình sẽ tạo một package tên là mypack và đưa class Person qua, việc này phục vụ cho những ví dụ phía dưới. Các bạn làm như sau trên Eclipse:

Các bài tập về lập trình hướng đối tượng java năm 2024

Các bài tập về lập trình hướng đối tượng java năm 2024

Rồi ta kéo class Person qua package mypack

Các bài tập về lập trình hướng đối tượng java năm 2024

Nếu các bạn sử dụng theo cách truyền thống. Thì bản chất package trong Java chính là folder chứa class mà thôi. Khi bạn xem trong source project, nó sẽ đổi như sau:

Các bài tập về lập trình hướng đối tượng java năm 2024

Và bạn sẽ để ý, trong các file java nó sẽ có sửa đổi như sau:

Các bài tập về lập trình hướng đối tượng java năm 2024

Việc thay đổi này do IDE Eclipse tự sửa cho chúng ta:

  • Khi ta tạo một class nằm trong một package nào đó thì phải khai báo package đầu tiên: Ở đây class Person nằm trong package mypack. Ta sẽ viết package mypack;
  • Khi ta sử dụng một class nằm ở packge khác, ta phải import qua để chương trình hiểu ta đang sử class của package nào. Theo đường dẫn class Person nằm trong package mypack, nên ở class HelloWorld ta sẽ viết import mypack.Person;

Lớp và đối tượng trong java

Trong bài này chúng ta sẽ học về lớp và đối tượng trong java. Trong phương pháp lập trình hướng đối tượng, chúng ta thiết kế chương trình bằng việc sử dụng các lớp và đối tượng.

Nội dung chính

Đối tượng

Một thực thể có trạng thái và hành vi được gọi là đối tượng. Ví dụ như máy pha cà phê, xe đạp, cái quạt...

Một đối tượng có ba đặc điểm:

  • Trạng thái: Đại diện cho dữ liệu (giá trị) của một đối tượng.
  • Hành vi: Đại diện cho hành vi (chức năng) của một đối tượng như gửi tiền, rút tiền, ...
  • Danh tính: Danh tính của một đối tượng thường được cài đặt thông qua một ID duy nhất. ID này được ẩn đối với user bên ngoài. Tuy nhiên nó được sử dụng trong nội bộ máy ảo JVM để định danh từng đối tượng.

Ví dụ: Bút chì là một đối tượng. Tên của nó là A, màu trắng, ... được gọi là trạng thái. Nó được sử dụng để viết, viết được gọi là hành vi.

Đối tượng(Object) là một thể hiện của một lớp(Class). Lớp là một mẫu hoặc thiết kế từ đó các đối tượng được tạo ra. Vì vậy, đối tượng là các thể hiện (kết quả) của một lớp.

Lớp

Một lớp là một nhóm đối tượng có các thuộc tính chung. Nó là một mẫu hoặc thiết kế từ đó các đối tượng được tạo ra.

Một lớp trong java có thể chứa:

  • Thành viên dữ liệu
  • Constructor
  • Phương thức
  • Khối lệnh
  • Lớp và Interface

Ví dụ đơn giản về Lớp và Đối tượng trong Java

Trong ví dụ này, chúng ta tạo một lớp Student có hai thành viên dữ liệu là id và name. Chúng ta đang tạo đối tượng của lớp Student bởi từ khóa new và in giá trị đối tượng.

class Student1{    
 int id; //thanh vien du lieu (cung la bien instance)    
 String name; //thanh vien du lieu (cung la bien instance)    
 public static void main(String args[]){    
  Student1 s1=new Student1(); //tao mot doi tuong Student    
  System.out.println(s1.id);    
  System.out.println(s1.name);    
 }    
}   ​

Các ví dụ đơn giản về lớp và đối tượng trong java

Ví dụ 1:

Trong ví dụ này, chúng tôi đã tạo ra một lớp Student có hai thành viên dữ liệu id và name. Chúng ta tạo ra các đối tượng của lớp Student bởi từ khóa new và in giá trị của các đối tượng.

public class Student {  
    int id; // thành viên dữ liệu  
    String name; // thành viên dữ liệu  
    public static void main(String args[]) {  
        Student student1 = new Student(); // tạo một đối tượng student1  
        System.out.println(student1.id);  
        System.out.println(student1.name);  
    }  
}

Kết quả:

Ví dụ 2:

public class Student2 {  
    int id;  
    String name;  
    // phương thức insertRecord  
    void insertRecord(int id, String name) {   
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student2 s1 = new Student2();  
        Student2 s2 = new Student2();  
        s1.insertRecord(111, "Anh");  
        s2.insertRecord(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

Kết quả:

Anh  
Tester​

Ví dụ 3:

public class Student3 {  
    int id;  
    String name;  
    // constructor  
    public Student3(int id, String name) {  
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student3 s1 = new Student3(111, "Anh");  
        Student3 s2 = new Student3(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

Kết quả:

Anh  
Tester​​

Có những cách nào để tạo đối tượng trong java?

Có vài cách để tạo đối tượng trong java, đó là:

  1. Sử dụng từ khóa new
  2. Sử dụng phương thức newInstance()
  3. Sử dụng phương thức clone()
  4. Sử dụng phương thức factory,...

Chúng ta sẽ chỉ học cách tạo đối tượng qua từ khóa "new" ở phần sau


Đối tượng Annonymous trong java

Annonymous nghĩa là vô danh. Một đối tượng không có tham chiếu gọi là đối tượng Annonymous.

Nếu bạn sử dụng đối tượng 1 lần duy nhất, thì lựa chọn tạo đối tượng Annonymous là tốt nhất trong trường hợp này.

Ví dụ:

public class Calculation {  
    void fact(int n) {  
        int giaithua = 1;  
        for (int i = 1; i <= n; i++) {  
            giaithua = giaithua * i;  
        }  
        System.out.println("Giai thừa của " + n + "  là: " + giaithua);  
    }  
    public static void main(String args[]) {  
        // gọi phương thức của đối tượng annonymous  
        new Calculation().fact(5);  
    }  
}​

Kết quả:


Sự khác nhau giữa lớp và đối tượng trong java

Sự khác nhau giữa lớp và đối tượng trong java được thống kê trong bảng sau:

No Đối tượng Lớp 1. Đối tượng là thể hiện của 1 lớp. Lớp là một khuân mẫu hay thiết kế để tạo ra các đối tượng. 2. Đối tượng là 1 thực thể trong thế giới thực như Bút chì, Xe đạp, ... Lớp là một nhóm các đối tượng tương tự nhau. 3. Đối tượng là 1 thực thể vật lý Lớp là 1 thực thể logic 4. Đối tượng được tạo ra chủ yếu từ từ khóa new. Ví dụ: Student s1=new Student(); Lớp được khai báo bằng việc sử dụng từ khóa class. Ví dụ: class Student{} 5. Đối tượng có thể được tạo nhiều lần. Lớp được khai báo 1 lần duy nhất. 6. Đối tượng được cấp bộ nhớ khi nó được tạo ra. Lớp không được cấp bộ nhớ khi nó được tạo ra. 7. Có rất nhiều cách để tạo ra đối tượng trong java như từ khóa new, phương thức newInstance(), phương thức clone(), phương thức factory và deserialization. Chỉ có một cách để định nghĩa lớp trong java sử dụng từ khoá class.

Bài tập rèn luyện

Bạn hãy viết chương trình khai báo lớp

Name: An  
Age: 25

4 với thông tin giống như sau:

Các bài tập về lập trình hướng đối tượng java năm 2024

Giải thích: hình trên là mô tả của lớp

Name: An  
Age: 25

4 với các thuộc tính và phương thức giống như sau:

  • Name: An Age: 25

    6 và

    Name: An Age: 25

    7 là hai thuộc tính dùng để lưu trữ tên và tuổi của đối tượng học sinh.
  • Name: An Age: 25

    8 là phương thức dùng để hiển thị thông tin của đối tượng ra màn hình. Ví dụ, nếu đối tượng có thuộc tính

    Name: An Age: 25

    9 thì khi gọi phương thức

    Name: An Age: 25

    8 thì màn hình sẽ hiển thị ra:

    Name: An Age: 25

  • Hoa 22

    1 là phương thức dùng để nhập dữ liệu cho thuộc tính

    Name: An Age: 25

    6 và

    Name: An Age: 25

    7 từ bàn phím. Ví dụ nếu bạn dùng phương thức này để nhập thông tin cho một đối tượng học sinh với

    Hoa 22

    4 như bên dưới:

    Hoa 22

    thì khi gọi phương thức

    Name: An Age: 25

    8 màn hình sẽ hiển thị ra:

    Name: Hoa Age: 22

Lý thuyết

Bài trước bạn đã hiểu sơ qua về lập trình hướng đối tượng và đã biết một số khái niệm như lớp, đối tượng, thuộc tính và phương thức.

Ở phần này bạn sẽ biết cách định nghĩa ra một lớp và sử dụng các đối tượng thuộc lớp này.

Về bản chất, lớp (class) là một kiểu dữ liệu do bạn tự định nghĩa và đối tượng chính là biến của kiểu dữ liệu này. Cú pháp để khai báo một lớp như sau:

public class Student {  
    int id; // thành viên dữ liệu  
    String name; // thành viên dữ liệu  
    public static void main(String args[]) {  
        Student student1 = new Student(); // tạo một đối tượng student1  
        System.out.println(student1.id);  
        System.out.println(student1.name);  
    }  
}

0

Ví dụ bạn có thể tạo ra lớp

Name: An  
Age: 25

4 với 2 thuộc tính là

Hoa  
22

7 và 2 phương thức là

Hoa  
22

1 và

Name: An  
Age: 25

8 giống như sau:

public class Student {  
    int id; // thành viên dữ liệu  
    String name; // thành viên dữ liệu  
    public static void main(String args[]) {  
        Student student1 = new Student(); // tạo một đối tượng student1  
        System.out.println(student1.id);  
        System.out.println(student1.name);  
    }  
}

1

Để khai báo đối tượng của một lớp bạn dùng từ khóa

Name: Hoa  
Age: 22

0. Ví dụ để khai báo một đối tượng thuộc lớp

Name: An  
Age: 25

4 bạn làm như sau:

public class Student {  
    int id; // thành viên dữ liệu  
    String name; // thành viên dữ liệu  
    public static void main(String args[]) {  
        Student student1 = new Student(); // tạo một đối tượng student1  
        System.out.println(student1.id);  
        System.out.println(student1.name);  
    }  
}

2

Để truy xuất tới các thuộc tính và phương thức của một đối tượng bạn dùng toán tử

Name: Hoa  
Age: 22

2:

public class Student {  
    int id; // thành viên dữ liệu  
    String name; // thành viên dữ liệu  
    public static void main(String args[]) {  
        Student student1 = new Student(); // tạo một đối tượng student1  
        System.out.println(student1.id);  
        System.out.println(student1.name);  
    }  
}

3

Kết quả khi chạy chương trình:

public class Student {  
    int id; // thành viên dữ liệu  
    String name; // thành viên dữ liệu  
    public static void main(String args[]) {  
        Student student1 = new Student(); // tạo một đối tượng student1  
        System.out.println(student1.id);  
        System.out.println(student1.name);  
    }  
}

4

Có thể thấy lớp và đối tượng chỉ đơn giản là kiểu dữ liệu và biến. Kiểu dữ liệu này khác các kiểu dữ liệu thông thường như int, string, double, ... ở chỗ nó có thể chứa được các phương thức và kiểu dữ liệu khác.

Đọc tới đây bạn đã biết cách định nghĩa một lớp và sử dụng đối tượng của lớp này, hãy quay lại phần bài tập và làm thử.

Hướng dẫn

Code mẫu:

public class Student {  
    int id; // thành viên dữ liệu  
    String name; // thành viên dữ liệu  
    public static void main(String args[]) {  
        Student student1 = new Student(); // tạo một đối tượng student1  
        System.out.println(student1.id);  
        System.out.println(student1.name);  
    }  
}

5


Tổng quan về Access Modifier (phạm vi truy cập) trong java

Bảng dưới đây mô tả khả năng truy cập của các Access Modifier trong java:

Access Modifier

Trong lớp

Trong package

Ngoài package bởi lớp con

Ngoài package

Private

Y

N

N

N

Default

Y

Y

N

N

Protected

Y

Y

Y

N

Public

Y

Y

Y

Y

Hình ảnh minh họa:

Các bài tập về lập trình hướng đối tượng java năm 2024

Phạm vi truy cập là gì?

Phạm vi truy cập (access modifiers) là xác định độ truy cập phạm vi vào dữ liệu của các thuộc tính, phương thức hoặc class.

Package (gói) là nhóm các class, interface hoặc các package con liên quan lại với nhau. Việc dùng package dùng để nhóm các class liên quan với nhau thành thư viện như thư viện swing, awt,…Ngoài ra, mục đích của package ngăn cản xung đột đặt tên, điều kiện truy cập, thuận tiện tìm kiếm và lưu trữ.


Các loại phạm vi truy cập

Có 4 loại phạm vi truy cập:

  • Private
  • (Default)
  • Protected
  • Public

1. Phạm vi truy cập Private

Private Access Modifier chỉ được truy cập trong phạm vi lớp.

Ví dụ về private access modifier trong java

Trong ví dụ, chúng ta tạo 2 lớp A và Simple. Lớp A chứa biến và phương thức được khai bao là private. Chúng ta cố gắng truy cập chúng từ bên ngoài lớp A. Điều này dẫn đến Compile time error:

public class Student {  
    int id; // thành viên dữ liệu  
    String name; // thành viên dữ liệu  
    public static void main(String args[]) {  
        Student student1 = new Student(); // tạo một đối tượng student1  
        System.out.println(student1.id);  
        System.out.println(student1.name);  
    }  
}

6

Vai trò của Private Constructor

Nếu bạn tạo bất kỳ constructor là private trong lớp, bạn sẽ không thể tạo instance của class bên ngoài nó. Ví dụ:

public class Student {  
    int id; // thành viên dữ liệu  
    String name; // thành viên dữ liệu  
    public static void main(String args[]) {  
        Student student1 = new Student(); // tạo một đối tượng student1  
        System.out.println(student1.id);  
        System.out.println(student1.name);  
    }  
}

7

Chú ý: Một lớp không thể là private hoặc protected, ngoại trừ lớp lồng nhau.


2. Phạm vi truy cập Default

Nếu bạn không khai báo modifier nào, thì nó chính là trường hợp mặc định. Default Access Modifier là chỉ được phép truy cập trong cùng package.

Ví dụ về Default Access Modifier trong Java

public class Student {  
    int id; // thành viên dữ liệu  
    String name; // thành viên dữ liệu  
    public static void main(String args[]) {  
        Student student1 = new Student(); // tạo một đối tượng student1  
        System.out.println(student1.id);  
        System.out.println(student1.name);  
    }  
}

8

public class Student {  
    int id; // thành viên dữ liệu  
    String name; // thành viên dữ liệu  
    public static void main(String args[]) {  
        Student student1 = new Student(); // tạo một đối tượng student1  
        System.out.println(student1.id);  
        System.out.println(student1.name);  
    }  
}

9

Trong ví dụ trên, phạm vi truy cập của lớp A và phương thức của msg() của nó là mặc định nên chúng không thể được truy cập từ bên ngoài package.


3. Phạm vi truy cập Protected

Protected access modifier được truy cập bên trong package và bên ngoài package nhưng phải kế thừa.

Protected access modifier có thể được áp dụng cho biến, phương thức, constructor. Nó không thể áp dụng cho lớp.

Ví dụ về protected access modifier trong Java:

public class Student2 {  
    int id;  
    String name;  
    // phương thức insertRecord  
    void insertRecord(int id, String name) {   
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student2 s1 = new Student2();  
        Student2 s2 = new Student2();  
        s1.insertRecord(111, "Anh");  
        s2.insertRecord(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

0

public class Student2 {  
    int id;  
    String name;  
    // phương thức insertRecord  
    void insertRecord(int id, String name) {   
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student2 s1 = new Student2();  
        Student2 s2 = new Student2();  
        s1.insertRecord(111, "Anh");  
        s2.insertRecord(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

1

Kết quả:

public class Student2 {  
    int id;  
    String name;  
    // phương thức insertRecord  
    void insertRecord(int id, String name) {   
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student2 s1 = new Student2();  
        Student2 s2 = new Student2();  
        s1.insertRecord(111, "Anh");  
        s2.insertRecord(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

2


4. Phạm vi truy cập public

Public access modifier được truy cập ở mọi nơi.

Ví dụ về public access modifier trong java:

public class Student2 {  
    int id;  
    String name;  
    // phương thức insertRecord  
    void insertRecord(int id, String name) {   
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student2 s1 = new Student2();  
        Student2 s2 = new Student2();  
        s1.insertRecord(111, "Anh");  
        s2.insertRecord(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

0

Tạo class B ở package khác và không cần kế thừa

public class Student2 {  
    int id;  
    String name;  
    // phương thức insertRecord  
    void insertRecord(int id, String name) {   
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student2 s1 = new Student2();  
        Student2 s2 = new Student2();  
        s1.insertRecord(111, "Anh");  
        s2.insertRecord(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

4

Kết quả:

public class Student2 {  
    int id;  
    String name;  
    // phương thức insertRecord  
    void insertRecord(int id, String name) {   
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student2 s1 = new Student2();  
        Student2 s2 = new Student2();  
        s1.insertRecord(111, "Anh");  
        s2.insertRecord(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

2

Như vậy chúng ta đã tìm hiểu các loại phạm vi truy cập trong lập trình hướng đối tượng


Từ khóa static làm gì?

Khi ta khai báo các thuộc tính, phương thức thì nó chỉ được sử dụng khi khởi tạo đối tượng, thông tin cũng thuộc đối tượng đó.

Có những lúc, ta cần những thông tin chung cho tất cả các đối tượng. Có nghĩa những thông tin đó lưu ở một vùng nhớ duy nhất. Từ khóa static sử dụng để quản lý bộ nhớ, khi những thành viên bên trong một lớp có từ khóa static thì nó thuộc về lớp, không phải thuộc về riêng một đối tượng nào đó.

Cách sử dụng static

Tạo biến tĩnh

Khi khai báo một biến tĩnh, biến đó có thể lưu thông tin chung cho tất cả các đối tượng.

Ví dụ: tạo một class Student của một trường ‘Kteam Education’, như vậy chỉ cần một bộ nhớ chung lưu thông tin tên trường, như vậy tiết kiệm bộ nhớ hơn. Ngoài ra, ta có thể tạo một biến đếm có bao nhiêu đối tượng Student đã được tạo ra:

Ta sẽ tạo một class Student như sau:

public class Student2 {  
    int id;  
    String name;  
    // phương thức insertRecord  
    void insertRecord(int id, String name) {   
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student2 s1 = new Student2();  
        Student2 s2 = new Student2();  
        s1.insertRecord(111, "Anh");  
        s2.insertRecord(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

6

Ta dùng 2 biến tĩnh là universityNam và total, mỗi khi tao khởi tạo một đối tượng của lớp Student, ta sẽ tăng giá trị total lên một đơn vị.

Tiếp theo, ta sẽ viết chương trình main:

public class Student2 {  
    int id;  
    String name;  
    // phương thức insertRecord  
    void insertRecord(int id, String name) {   
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student2 s1 = new Student2();  
        Student2 s2 = new Student2();  
        s1.insertRecord(111, "Anh");  
        s2.insertRecord(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

7

Trong đoạn chương trình, chúng ta đã thử truy xuất biến tĩnh từ lớp hoặc từ đối tượng.

Các bài tập về lập trình hướng đối tượng java năm 2024


Tạo phương thức tĩnh

Phương thức tĩnh cũng giống như biến tĩnh, có thể gọi mà không cần khởi tạo đối tượng. Phương thức tĩnh rất thích hợp cho những class thư viện viết sẵn, không cần khởi tạo mà chỉ cần gọi ra để chạy chương trình.

Ví dụ: giới thiệu trường học từ class Student.

Tại class Student

public class Student2 {  
    int id;  
    String name;  
    // phương thức insertRecord  
    void insertRecord(int id, String name) {   
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student2 s1 = new Student2();  
        Student2 s2 = new Student2();  
        s1.insertRecord(111, "Anh");  
        s2.insertRecord(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

8

Tại chương trình main

public class Student2 {  
    int id;  
    String name;  
    // phương thức insertRecord  
    void insertRecord(int id, String name) {   
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student2 s1 = new Student2();  
        Student2 s2 = new Student2();  
        s1.insertRecord(111, "Anh");  
        s2.insertRecord(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

9

Các bài tập về lập trình hướng đối tượng java năm 2024

Tuy nhiên, phương thức static không thể tác động đến thuộc tính và phương thức liên quan đối tượng (non-static).

Các bài tập về lập trình hướng đối tượng java năm 2024


Khối static

Khối static được sử dụng cho mục đích khởi tạo giá trị các biến static. Khối sẽ được thực hiện khi lớp chứa nó được load vào trong bộ nhớ.

Trong một lớp có thể nhiều khối tùy ý. Các khối này sẽ chạy cùng nhau, và chạy trước cả chương trình main của lớp đó.

Ví dụ: ta tạo khối static ở class HelloWorld

Anh  
Tester​

0

Kết quả

Anh  
Tester​

1

Như vậy chúng ta đã tìm hiểu từ khóa static trong lập trình hướng đối tượng

Tính kế thừa trong Java

Phần này chúng ta sẽ tìm hiểu những vấn đề sau:

  • Khái niệm kế thừa
  • Khai báo và sử dụng kế thừa
  • Chú ý về kế thừa

Khái niệm kế thừa

Kế thừa có nghĩa là thừa hưởng lại, ví dụ như tài sản của ba mẹ sẽ được giao lại cho con cái.

Kế thừa trong lập trình (Inheritance) có nghĩa là một lớp sẽ thừa hưởng lại những thuộc tính, phương thức từ lớp khác.

Việc sử dụng kế thừa nhằm tái sử dụng code đã viết trước đó, thuận tiện trong việc bảo trì và nâng cấp chương trình.


Khai báo và sử dụng kế thừa

Cú pháp:

Anh  
Tester​

2

Ví dụ: ta có 2 lớp Person và Student như sau

Các bài tập về lập trình hướng đối tượng java năm 2024

Ta thấy 2 lớp Person và Student có chung thuộc tính và phương thức. Ta sẽ để nguyên code ở lớp Person lại:

Anh  
Tester​

3

Bây giờ ta chỉ cần cho lớp Student kế thừa Person như sau:

Anh  
Tester​

4

Trong phương thức khởi tạo Student, ta sẽ dùng từ khóa super để cho lớp con truy cập các những thứ liên quan đến lớp cha. Như ví dụ trên thì ta dùng super() để gọi phương thức khởi tạo lớp cha.

Tiếp theo, ta thử khởi tạo đối tượng Student và gọi phương thức getInfo():

Anh  
Tester​

5

Theo kết quả, đối tượng a sử dụng được phương thức getInfo() từ lớp cha

Các bài tập về lập trình hướng đối tượng java năm 2024


Chú ý về kế thừa

Slogan đặc trưng kế thừa: “Cha có thì con có, con có chưa chắc cha đã có”

Tính chất kế thừa các ngôn ngữ lập trình hướng đối tượng đa số đều tương đồng với nhau về tính chất. Có thể các bạn không nhớ khái niệm và cú pháp, nhưng chỉ cần hiểu câu nói trên là bạn đã hiểu về kế thừa.

Ví dụ: Như ví dụ trước thì lớp Student kế thừa Person, ngoài những thuộc tính kế thừa ra, ta muốn thêm thuộc tính universityName cho Student

Anh  
Tester​

6

Như vậy theo đúng tính chất: lớp cha Person có name, age, height thì lớp con Student có. Lớp con Student có universityName thì lớp cha Person không có.


Tận dụng từ khóa super để bảo trì và nâng cấp code

Từ khóa super mục đích chính truy cập những phương thức của lớp cha. Trong việc phát triển phần mềm, ta cần nâng cấp chương trình. Việc tận dụng từ khóa super sẽ giúp ta vừa tận dụng những dòng code trước đó và viết tiếp code mới.

Ví dụ: ta thấy phương thức getInfo() chỉ trả về thông tin name, age, height. Bây giờ, ta sẽ nâng cấp phương thức có thể trả về thông tin universityName ở lớp Student

Anh  
Tester​

7

Ta thử khởi tạo để kiểm tra:

Anh  
Tester​

8

Các bài tập về lập trình hướng đối tượng java năm 2024

Flow của chương trình có thể hiểu như sau:

Các bài tập về lập trình hướng đối tượng java năm 2024

Như vậy chúng ta đã tìm hiểu kế thừa trong lập trình hướng đối tượng

Tính đóng gói trong Java

Tính đóng gói trong java là kỹ thuật ẩn giấu thông tin không liên quan và hiện thị ra thông liên quan. Mục đích chính của đóng gói trong java là giảm thiểu mức độ phức tạp phát triển phần mềm.

Các bài tập về lập trình hướng đối tượng java năm 2024

Đóng gói cũng được sử dụng để bảo vệ trạng thái bên trong của một đối tượng. Bởi việc ẩn giấu các biến biểu diễn trạng thái của đối tượng. Việc chỉnh sửa đối tượng được thực hiện, xác nhận thông qua các phương thức. Hơn nữa, việc ẩn giấu các biến thì các lớp sẽ không chia sẻ thông tin với nhau được. Điều này làm giảm số lượng khớp nối có thể có trong một ứng dụng.

Lợi ích của đóng gói trong java

Bạn có thể tạo lớp read-only hoặc write-only bằng việc cài đặt phương thức setter hoặc getter.

Bạn có thể kiểm soát đối với dữ liệu. Giả sử bạn muốn đặt giá trị của id chỉ lớn hơn 100 bạn có thể viết logic bên trong lớp setter.

Ví dụ về đóng gói trong java

Hãy xem ví dụ sau về đóng gói trong java với một lớp chỉ có một trường và các phướng thức setter và getter của nó.

Class: Student.java

Anh  
Tester​

9

Class: Main.java

public class Student3 {  
    int id;  
    String name;  
    // constructor  
    public Student3(int id, String name) {  
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student3 s1 = new Student3(111, "Anh");  
        Student3 s2 = new Student3(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

0

Kết quả:

public class Student3 {  
    int id;  
    String name;  
    // constructor  
    public Student3(int id, String name) {  
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student3 s1 = new Student3(111, "Anh");  
        Student3 s2 = new Student3(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

1

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ụ:

public class Student3 {  
    int id;  
    String name;  
    // constructor  
    public Student3(int id, String name) {  
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student3 s1 = new Student3(111, "Anh");  
        Student3 s2 = new Student3(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

2

public class Student3 {  
    int id;  
    String name;  
    // constructor  
    public Student3(int id, String name) {  
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student3 s1 = new Student3(111, "Anh");  
        Student3 s2 = new Student3(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

3


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.

public class Student3 {  
    int id;  
    String name;  
    // constructor  
    public Student3(int id, String name) {  
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student3 s1 = new Student3(111, "Anh");  
        Student3 s2 = new Student3(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

4

Kết quả:

public class Student3 {  
    int id;  
    String name;  
    // constructor  
    public Student3(int id, String name) {  
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student3 s1 = new Student3(111, "Anh");  
        Student3 s2 = new Student3(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

5

Ví dụ 2: Bank (ngân hàng)

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%.

Các bài tập về lập trình hướng đối tượng java năm 2024
public class Student3 {  
    int id;  
    String name;  
    // constructor  
    public Student3(int id, String name) {  
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student3 s1 = new Student3(111, "Anh");  
        Student3 s2 = new Student3(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

6

Kết quả:

public class Student3 {  
    int id;  
    String name;  
    // constructor  
    public Student3(int id, String name) {  
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student3 s1 = new Student3(111, "Anh");  
        Student3 s2 = new Student3(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

7

Ví dụ 3: Shape:

public class Student3 {  
    int id;  
    String name;  
    // constructor  
    public Student3(int id, String name) {  
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student3 s1 = new Student3(111, "Anh");  
        Student3 s2 = new Student3(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

8

Kết quả:

public class Student3 {  
    int id;  
    String name;  
    // constructor  
    public Student3(int id, String name) {  
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student3 s1 = new Student3(111, "Anh");  
        Student3 s2 = new Student3(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

9


Đ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.

Anh  
Tester​​

0

Kết quả:

Anh  
Tester​​

1

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

Ví dụ 1:

Anh  
Tester​​

2

Kết quả:

Anh  
Tester​​

3

Ví dụ 2:

Anh  
Tester​​

4

Kết quả:

Anh  
Tester​​

5

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.

Nạp chồng phương thức trong Java

Nạp chồng phương thức (method overloading)

Nạp chồng phương thức trong java xảy ra nếu một lớp có nhiều phương thức có tên giống nhau nhưng khác nhau về kiểu dữ liệu hoặc số lượng các tham số.

Giả sử bạn phải thực hiện tính tổng của các số đã cho với bất kỳ số lượng các đối số, nếu bạn viết phương thức a(int, int) cho 2 tham số, b(int, int, int) cho 3 tham số điều này có thể gây khó hiểu cho các lập trình viên khác về ý nghĩa của các phương thức đó vì chúng có tên khác nhau.

Lợi ích của nạp chồng phương thức

Sử dụng nạp chồng phương thức giúp tăng khả năng đọc hiểu chương trình.

Các cách nạp chồng phương thức

Có 2 cách nạp chồng phương thức trong java

  • Thay đổi số lượng các tham số
  • Thay đổi kiểu dữ liệu của các tham số

Trong java, không thể nạp chồng phương thức bằng cách chỉ thay đổi kiểu trả về của phương thức.


1. Nạp chồng phương thức: thay đổi số lượng các tham số

Trong ví dụ này, chúng ta cần tạo 2 phương thức, phương thức add() đầu tiên thực hiện việc tính tổng của 2 số, phương thức thứ hai thực hiện việc tính tổng của 3 số. Sử dụng phương thức static để gọi hàm thông qua tên class thay vì phải tạo thể hiên của lớp.

Anh  
Tester​​

6

Kết quả:

Anh  
Tester​​

7

2. Nạp chồng phương thức: thay đổi kiểu dữ liệu của các tham số

Trong ví dụ này, chúng ta sẽ tạo ra 2 phương thức có kiểu dữ liệu khác nhau. Phương thức add() đầu tiên nhận 2 đổi số có kiểu giá trị là integer, phương thức thứ hai nhận 2 đổi số có kiểu giá trị là double.

Anh  
Tester​​

8

Kết quả:

Anh  
Tester​​

9


Các câu hỏi về nạp chồng phương thức trong java

Câu hỏi 1: Tại sao không thể nạp chồng phương thức bằng cách chỉ thay đổi kiểu trả về của phương thức?

Trong java, không thể nạp chồng phương thức bằng cách chỉ thay đổi kiểu trả về của phương thức bởi vì không biết phương thức nào sẽ được gọi.

Ví dụ:

public class Calculation {  
    void fact(int n) {  
        int giaithua = 1;  
        for (int i = 1; i <= n; i++) {  
            giaithua = giaithua * i;  
        }  
        System.out.println("Giai thừa của " + n + "  là: " + giaithua);  
    }  
    public static void main(String args[]) {  
        // gọi phương thức của đối tượng annonymous  
        new Calculation().fact(5);  
    }  
}​

0

Kết quả:

public class Calculation {  
    void fact(int n) {  
        int giaithua = 1;  
        for (int i = 1; i <= n; i++) {  
            giaithua = giaithua * i;  
        }  
        System.out.println("Giai thừa của " + n + "  là: " + giaithua);  
    }  
    public static void main(String args[]) {  
        // gọi phương thức của đối tượng annonymous  
        new Calculation().fact(5);  
    }  
}​

1

Câu hỏi 2: Có thể nạp chồng phương thức main() không?

Có, bạn có thể nạp chồng n phương thức main. Nhưng JVM chỉ gọi phương thức main() có tham số truyền vào là một mảng String. Ví dụ:

public class Calculation {  
    void fact(int n) {  
        int giaithua = 1;  
        for (int i = 1; i <= n; i++) {  
            giaithua = giaithua * i;  
        }  
        System.out.println("Giai thừa của " + n + "  là: " + giaithua);  
    }  
    public static void main(String args[]) {  
        // gọi phương thức của đối tượng annonymous  
        new Calculation().fact(5);  
    }  
}​

2

Kết quả:

public class Calculation {  
    void fact(int n) {  
        int giaithua = 1;  
        for (int i = 1; i <= n; i++) {  
            giaithua = giaithua * i;  
        }  
        System.out.println("Giai thừa của " + n + "  là: " + giaithua);  
    }  
    public static void main(String args[]) {  
        // gọi phương thức của đối tượng annonymous  
        new Calculation().fact(5);  
    }  
}​

3

Nạp chồng phương thức và sự thay đổi kiểu giá trị

Kiểu dữ liệu của đối số truyền vào được thay đổi sang kiểu dữ liệu khác (tự động ép kiểu) nếu giá trị của đối số đó không phù hợp với kiểu dữ liệu của tham số đã được đinh nghĩa. Để hiểu khái niệm này hãy xem ảnh sau:

Các bài tập về lập trình hướng đối tượng java năm 2024

Kiểu byte có thể được ép sang các kiểu short, int, long, float hoặc double. Kiểu dữ liệu short có thể được ép sang các kiểu int, long, float hoặc double. Kiểu dữ liệu char có thể được ép sang các kiểu int, long, float or double…


Ví dụ 1:

public class Calculation {  
    void fact(int n) {  
        int giaithua = 1;  
        for (int i = 1; i <= n; i++) {  
            giaithua = giaithua * i;  
        }  
        System.out.println("Giai thừa của " + n + "  là: " + giaithua);  
    }  
    public static void main(String args[]) {  
        // gọi phương thức của đối tượng annonymous  
        new Calculation().fact(5);  
    }  
}​

4

Kết quả:

public class Calculation {  
    void fact(int n) {  
        int giaithua = 1;  
        for (int i = 1; i <= n; i++) {  
            giaithua = giaithua * i;  
        }  
        System.out.println("Giai thừa của " + n + "  là: " + giaithua);  
    }  
    public static void main(String args[]) {  
        // gọi phương thức của đối tượng annonymous  
        new Calculation().fact(5);  
    }  
}​

5


Ví dụ 2: nếu không có kiểu đối số nào phù hợp, chuyển đổi kiểu sẽ không được thực hiện.

public class Calculation {  
    void fact(int n) {  
        int giaithua = 1;  
        for (int i = 1; i <= n; i++) {  
            giaithua = giaithua * i;  
        }  
        System.out.println("Giai thừa của " + n + "  là: " + giaithua);  
    }  
    public static void main(String args[]) {  
        // gọi phương thức của đối tượng annonymous  
        new Calculation().fact(5);  
    }  
}​

6

Kết quả:

public class Calculation {  
    void fact(int n) {  
        int giaithua = 1;  
        for (int i = 1; i <= n; i++) {  
            giaithua = giaithua * i;  
        }  
        System.out.println("Giai thừa của " + n + "  là: " + giaithua);  
    }  
    public static void main(String args[]) {  
        // gọi phương thức của đối tượng annonymous  
        new Calculation().fact(5);  
    }  
}​

7


Ví dụ 3: không có kiểu đối số nào phụ hợp trong phương thức và mỗi phương thức thay đổi số đối số tương tự nhau. Th này sẽ không xác định được phương thức nào được gọi.

public class Calculation {  
    void fact(int n) {  
        int giaithua = 1;  
        for (int i = 1; i <= n; i++) {  
            giaithua = giaithua * i;  
        }  
        System.out.println("Giai thừa của " + n + "  là: " + giaithua);  
    }  
    public static void main(String args[]) {  
        // gọi phương thức của đối tượng annonymous  
        new Calculation().fact(5);  
    }  
}​

8

Kết quả:

public class Calculation {  
    void fact(int n) {  
        int giaithua = 1;  
        for (int i = 1; i <= n; i++) {  
            giaithua = giaithua * i;  
        }  
        System.out.println("Giai thừa của " + n + "  là: " + giaithua);  
    }  
    public static void main(String args[]) {  
        // gọi phương thức của đối tượng annonymous  
        new Calculation().fact(5);  
    }  
}​

9

Một kiểu không được tự động ép sang kiểu bé hơn, ví dụ kiểu double không được ép sang bất kỳ kiểu nào khác.


Ghi đè phương thức trong java

Ghi đè phương thức (method overriding)

Ghi đè phương thức trong java xảy ra nếu lớp con có phương thức giống lớp cha.

Nói cách khác, nếu lớp con cung cấp sự cài đặt cụ thể cho phương thức đã được cung cấp bởi một lớp cha của nó được gọi là ghi đè phương thức (method overriding) trong java.

Sử dụng ghi đè phương thức trong java

  • Ghi đè phương thức được sử dụng để cung cấp cài đặt đặc biệt của một phương thức mà đã được định nghĩa ở lớp cha.
  • Ghi đè phương thức được sử dụng cho đa hình runtime.

Các nguyên tắc ghi đè phương thức trong java

  1. Phương thức phải có tên giống với lớp cha.
  2. Phương thức phải có tham số giống với lớp cha.
  3. Lớp con và lớp cha có mối quan hệ kế thừa.

Ví dụ ghi đè phương thức trong java

Trong ví dụ này, chúng ta định nghĩa phương thức run() trong lớp con giống như đã được định nghĩa trong lớp cha, nhưng được cài đặt rõ ràng trong lớp con. Tên và tham số của phương thức là giống nhau, 2 lớp cha và con có quan hệ kế thừa.

Name: An  
Age: 25

0

Kết quả:

Name: An  
Age: 25

1

Ví dụ thực tế về ghi đè phương thức trong java

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%.

Các bài tập về lập trình hướng đối tượng java năm 2024

Dưới đây là cài đặt cho ví dụ trên:

Name: An  
Age: 25

2

Kết quả:

public class Student3 {  
    int id;  
    String name;  
    // constructor  
    public Student3(int id, String name) {  
        this.id = id;  
        this.name = name;  
    }  
    // phương thức displayInformation  
    void displayInformation() {  
        System.out.println(id + " " + name);  
    }  
    public static void main(String args[]) {  
        Student3 s1 = new Student3(111, "Anh");  
        Student3 s2 = new Student3(222, "Tester");  
        s1.displayInformation();  
        s2.displayInformation();  
    }  
}​

7


Câu hỏi về ghi đè phương thức trong java

Có ghi đè được phương thức static không?

Không, phương thức static không thể ghi đè được, bằng chứng là đa hình runtime, vấn đề này sẽ được học trong bài sau.

Tại sao không ghi đè được phương thức static?

Vì phương thức static được ràng buộc với class còn phương thức instance được ràng buộc với đối tượng. Static thuộc về vùng nhớ class còn instance thuộc về vùng nhớ heap.