---
# System prepended metadata

title: Các tính chất của lập trình hướng đối tượng

---

Lập trình hướng đối tượng (OOP) là một phương pháp lập trình mà trong đó, mọi thực thể trong chương trình được coi là một đối tượng có thể chứa dữ liệu và các phương thức xử lý dữ liệu đó. Dưới đây là bốn tính chất quan trọng của lập trình hướng đối tượng:

### 1. Tính đóng (Encapsulation):
Tính đóng đề cập đến việc gói gọn dữ liệu và các phương thức xử lý dữ liệu trong một đối tượng để bảo vệ chúng khỏi sự truy cập trực tiếp từ bên ngoài. Điều này giúp ẩn thông tin và ngăn chặn việc sửa đổi trực tiếp dữ liệu, đảm bảo tính nhất quán của chương trình.

**Ví dụ trong Java:**
```java
public class NhanVien {
    private String ten;
    private int tuoi;

    // Các phương thức getter và setter để truy cập dữ liệu
    public String getTen() {
        return ten;
    }

    public void setTen(String ten) {
        this.ten = ten;
    }

    public int getTuoi() {
        return tuoi;
    }

    public void setTuoi(int tuoi) {
        this.tuoi = tuoi;
    }
}
```

### 2. Tính kế thừa (Inheritance):
Tính kế thừa cho phép một lớp (class) mới có thể sử dụng các thuộc tính và phương thức của lớp hiện có (cha). Điều này giúp tái sử dụng mã nguồn, giảm độ phức tạp của chương trình và tăng tính linh hoạt.

**Ví dụ trong Java:**
```java
public class NhanVienManager extends NhanVien {
    // Các phương thức và thuộc tính riêng của lớp NhanVienManager
}
```

### 3. Tính đa hình (Polymorphism):
Tính đa hình cho phép một phương thức có thể có nhiều hình thức hoạt động khác nhau dựa trên đối tượng mà nó đang thao tác. Điều này giúp giảm thiểu sự phụ thuộc vào kiểu dữ liệu cụ thể và tăng khả năng mở rộng của chương trình.

**Ví dụ trong Java:**
```java
public interface Xe {
    void chay();
}

public class XeHoi implements Xe {
    public void chay() {
        System.out.println("Xe hơi đang chạy.");
    }
}

public class XeMay implements Xe {
    public void chay() {
        System.out.println("Xe máy đang chạy.");
    }
}
```

### 4. Tính trừu tượng (Abstraction):
Tính trừu tượng là khả năng ẩn đi các chi tiết cụ thể của một đối tượng và chỉ hiển thị thông tin cần thiết. Điều này giúp giảm sự phức tạp của chương trình và tăng tính bảo mật và bảo trì.

**Ví dụ trong Java:**
```java
abstract class Hinh {
    abstract void ve();
}

class HinhTron extends Hinh {
    void ve() {
        System.out.println("Vẽ hình tròn");
    }
}

class HinhVuong extends Hinh {
    void ve() {
        System.out.println("Vẽ hình vuông");
    }
}
```

Các tính chất này cùng nhau tạo nên một cơ sở cho lập trình hướng đối tượng, giúp cải thiện tính module, sửa đổi dễ dàng, và tái sử dụng mã nguồn một cách hiệu quả.

<hr>

Tính kế thừa là một trong những tính chất quan trọng của lập trình hướng đối tượng, và nó cho phép một lớp (hoặc đối tượng) mới có thể sử dụng các thuộc tính và phương thức của một lớp hiện có. Trong Java, điều này được thực hiện thông qua việc sử dụng từ khóa `extends`.

Dưới đây là một ví dụ chi tiết về tính kế thừa trong Java, sử dụng lớp `NhanVien` và lớp `NhanVienManager`:

```java
// Lớp cha (superclass) NhanVien
public class NhanVien {
    private String ten;
    private int tuoi;

    public NhanVien(String ten, int tuoi) {
        this.ten = ten;
        this.tuoi = tuoi;
    }

    public String getTen() {
        return ten;
    }

    public void setTen(String ten) {
        this.ten = ten;
    }

    public int getTuoi() {
        return tuoi;
    }

    public void setTuoi(int tuoi) {
        this.tuoi = tuoi;
    }

    public void hienThiThongTin() {
        System.out.println("Tên nhân viên: " + ten);
        System.out.println("Tuổi: " + tuoi);
    }
}
```

Ở đây, `NhanVien` là lớp cha chứa thông tin cơ bản về một nhân viên. Bây giờ, chúng ta muốn tạo một lớp con (subclass) `NhanVienManager` để đại diện cho một quản lý nhân viên. Lớp con này sẽ kế thừa các thuộc tính và phương thức từ lớp cha.

```java
// Lớp con (subclass) NhanVienManager kế thừa từ NhanVien
public class NhanVienManager extends NhanVien {
    private String chucVu;

    public NhanVienManager(String ten, int tuoi, String chucVu) {
        super(ten, tuoi); // Gọi constructor của lớp cha
        this.chucVu = chucVu;
    }

    public String getChucVu() {
        return chucVu;
    }

    public void setChucVu(String chucVu) {
        this.chucVu = chucVu;
    }

    // Phương thức này overrides (ghi đè) phương thức của lớp cha
    @Override
    public void hienThiThongTin() {
        super.hienThiThongTin(); // Gọi phương thức của lớp cha
        System.out.println("Chức vụ: " + chucVu);
    }

    public void quanLyCongViec() {
        System.out.println("Quản lý công việc của nhân viên");
    }
}
```

Trong ví dụ này, `NhanVienManager` kế thừa từ `NhanVien`, nghĩa là nó sẽ có tất cả các thuộc tính và phương thức của `NhanVien`, và có thể mở rộng chúng hoặc thêm mới những thuộc tính và phương thức riêng (như `chucVu` và `quanLyCongViec`).

Kế thừa giúp tái sử dụng mã nguồn, giảm độ phức tạp của chương trình, và tăng tính linh hoạt bằng cách cho phép mở rộng chức năng của một lớp hiện có mà không làm thay đổi mã nguồn của lớp đó.

Trong lập trình Java, từ khóa `super` và `this` được sử dụng để tham chiếu đến các thành phần của lớp hiện tại hoặc lớp cha.

### 1. Từ khóa `super`:
- `super` được sử dụng để tham chiếu đến các thành phần của lớp cha.
- Nó có thể được sử dụng để gọi constructor của lớp cha, tránh xung đột giữa tên biến của lớp cha và lớp con, và gọi phương thức của lớp cha.

**Ví dụ sử dụng `super` để gọi constructor của lớp cha:**
```java
public class NhanVien {
    private String ten;

    public NhanVien(String ten) {
        this.ten = ten;
    }
}

public class NhanVienManager extends NhanVien {
    private String chucVu;

    public NhanVienManager(String ten, String chucVu) {
        super(ten); // Gọi constructor của lớp cha
        this.chucVu = chucVu;
    }
}
```

### 2. Từ khóa `this`:
- `this` được sử dụng để tham chiếu đến các thành phần của lớp hiện tại.
- Nó giúp phân biệt giữa các biến của lớp và tham số của phương thức cùng tên, hoặc giữa các trường và tham số của constructor.

**Ví dụ sử dụng `this` để phân biệt biến trường và tham số trong constructor:**
```java
public class NhanVien {
    private String ten;

    public NhanVien(String ten) {
        this.ten = ten;
    }
}
```

Trong trường hợp này, `this.ten` được sử dụng để tham chiếu đến biến trường `ten` của lớp hiện tại.

**Lưu ý:** Cả `super` và `this` đều phải được sử dụng trong ngữ cảnh hợp lý để tránh nhầm lẫn và lỗi logic trong chương trình.

<hr>

Tính đa hình là một trong những tính chất quan trọng của lập trình hướng đối tượng, và nó cho phép một phương thức có thể thực hiện nhiều hình thức hoạt động khác nhau dựa trên đối tượng mà nó đang thao tác. Tính đa hình giúp giảm sự phụ thuộc vào kiểu dữ liệu cụ thể, tăng tính linh hoạt và mở rộng của chương trình. Trong Java, đa hình có thể được thực hiện thông qua hai cơ chế: **ghi đè (override)** và **nạp chồng (overloading)**.

### Ghi đè (Override):

Ghi đè xảy ra khi một lớp con cung cấp triển khai (implementation) cho một phương thức đã được định nghĩa trong lớp cha. Lớp con có thể thay đổi cách thức hoạt động của phương thức mà nó đang ghi đè.

**Ví dụ:**
```java
public class Hinh {
    public void ve() {
        System.out.println("Vẽ một hình");
    }
}

public class HinhTron extends Hinh {
    @Override
    public void ve() {
        System.out.println("Vẽ hình tròn");
    }
}

public class HinhVuong extends Hinh {
    @Override
    public void ve() {
        System.out.println("Vẽ hình vuông");
    }
}
```

Ở đây, `HinhTron` và `HinhVuong` đều ghi đè phương thức `ve` từ lớp cha `Hinh`. Khi gọi phương thức `ve` trên một đối tượng của lớp con, phương thức của lớp con sẽ được gọi.

### Nạp chồng (Overloading):

Nạp chồng xảy ra khi một lớp có nhiều phương thức cùng tên nhưng với danh sách tham số khác nhau. Điều này cho phép cùng một phương thức có thể thực hiện nhiều hành động khác nhau tùy thuộc vào số lượng và kiểu dữ liệu của tham số được truyền vào.

**Ví dụ:**
```java
public class CongCu {
    public int cong(int a, int b) {
        return a + b;
    }

    public double cong(double a, double b) {
        return a + b;
    }
}
```

Ở đây, `CongCu` có hai phương thức `cong` với cùng tên nhưng khác nhau về kiểu dữ liệu của tham số. Khi gọi phương thức `cong`, Java sẽ xác định phương thức nào sẽ được gọi dựa trên kiểu dữ liệu của các đối số được truyền vào.

Tính đa hình giúp mã nguồn trở nên linh hoạt hơn, vì nó cho phép chương trình thích ứng với các đối tượng cụ thể mà nó đang xử lý mà không cần biết chi tiết về kiểu dữ liệu của chúng. Điều này làm tăng tính tái sử dụng mã nguồn và giảm sự phụ thuộc vào kiểu dữ liệu cụ thể.

Abstract class và interface là hai khái niệm quan trọng trong lập trình hướng đối tượng, và chúng đều có thể được sử dụng để thể hiện tính đa hình.

### Abstract Class (Lớp Trừu Tượng):

Lớp trừu tượng là một lớp mà không thể được khởi tạo (tạo đối tượng trực tiếp từ nó). Nó được sử dụng để định nghĩa các phương thức mà các lớp con bắt buộc phải thực hiện. Một lớp trừu tượng có thể chứa cả phương thức trừu tượng và phương thức có triển khai.

**Ví dụ:**
```java
// Lớp trừu tượng
abstract class Hinh {
    // Phương thức trừu tượng
    public abstract void ve();

    // Phương thức có triển khai
    public void thongTin() {
        System.out.println("Đây là một hình.");
    }
}

// Lớp con thực hiện từ lớp trừu tượng
class HinhTron extends Hinh {
    @Override
    public void ve() {
        System.out.println("Vẽ hình tròn");
    }
}
```

### Interface (Giao Diện):

Giao diện là một tập hợp các phương thức trừu tượng mà mọi lớp implement (thực thi) nó bắt buộc phải định nghĩa. Một lớp có thể implement nhiều giao diện, cung cấp khả năng đa kế thừa.

**Ví dụ:**
```java
// Giao diện
interface Xe {
    void chay();
}

// Lớp implement giao diện
class XeHoi implements Xe {
    @Override
    public void chay() {
        System.out.println("Xe hơi đang chạy.");
    }
}

// Lớp khác implement giao diện
class XeMay implements Xe {
    @Override
    public void chay() {
        System.out.println("Xe máy đang chạy.");
    }
}
```

### Thể Hiện Tính Đa Hình:

Cả abstract class và interface đều cung cấp cơ chế để thể hiện tính đa hình. Đối với abstract class, điều này thường được thực hiện thông qua việc ghi đè các phương thức trừu tượng. Đối với interface, các lớp implement giao diện bắt buộc phải định nghĩa tất cả các phương thức trong giao diện.

**Ví dụ về tính đa hình thông qua abstract class và interface:**
```java
// Sử dụng abstract class
Hinh hinhTron = new HinhTron();
hinhTron.ve();      // Gọi phương thức của HinhTron

// Sử dụng interface
XeHoi xeHoi = new XeHoi();
xeHoi.chay();       // Gọi phương thức của XeHoi

XeMay xeMay = new XeMay();
xeMay.chay();       // Gọi phương thức của XeMay
```

Trong ví dụ trên, chúng ta có thể thấy cách sử dụng abstract class và interface để tạo ra tính đa hình trong Java. Cả hai khái niệm này giúp chương trình trở nên linh hoạt và dễ mở rộng.

<hr>

Tính đóng gói là một trong những tính chất quan trọng của lập trình hướng đối tượng, và nó đề cập đến việc gói gọn dữ liệu và các phương thức xử lý dữ liệu trong một đối tượng sao cho chúng không thể trực tiếp được truy cập từ bên ngoài lớp đó. Mục tiêu là ẩn thông tin và chỉ cho phép truy cập thông qua các phương thức công cộng (public methods).

### Tại sao cần tính đóng gói:

1. **Bảo vệ Dữ liệu:** Tính đóng gói giúp bảo vệ dữ liệu bằng cách không cho phép truy cập trực tiếp từ bên ngoài. Điều này giúp ngăn chặn sự thay đổi ngẫu nhiên và không kiểm soát của dữ liệu.

2. **Giảm Sự Phụ Thuộc:** Việc ẩn chi tiết cài đặt bên trong một đối tượng giúp giảm sự phụ thuộc của các phần khác nhau của chương trình lẫn nhau. Các đối tượng có thể tương tác thông qua giao diện công cộng mà không cần biết chi tiết cài đặt của nhau.

3. **Tăng Bảo Mật:** Tính đóng gói giúp tăng cường bảo mật bằng cách ngăn chặn truy cập trực tiếp và kiểm soát việc thay đổi dữ liệu thông qua các phương thức công cộng.

### Cách Thực Hiện Tính Đóng Gói:

1. **Sử dụng Phạm Vi Truy Cập (Access Modifiers):** Trong Java, sử dụng từ khóa như `private`, `protected`, và `public` để xác định phạm vi truy cập của các thành phần lớp (biến và phương thức).

    ```java
    public class NhanVien {
        private String ten; // Biến private, chỉ có thể truy cập trong lớp NhanVien

        public void setTen(String ten) {
            this.ten = ten;
        }

        public String getTen() {
            return ten;
        }
    }
    ```

2. **Encapsulation (Đóng Gói):** Đóng gói là việc đặt các biến thành viên là private và cung cấp các phương thức công cộng để truy cập và thay đổi giá trị của chúng.

    ```java
    public class NhanVien {
        private String ten;

        // Phương thức công cộng để đặt giá trị cho biến private
        public void setTen(String ten) {
            this.ten = ten;
        }

        // Phương thức công cộng để lấy giá trị của biến private
        public String getTen() {
            return ten;
        }
    }
    ```

3. **Getter và Setter:** Sử dụng phương thức getter để lấy giá trị của biến và setter để đặt giá trị của biến. Điều này giúp kiểm soát việc truy cập và thay đổi giá trị của biến.

    ```java
    public class NhanVien {
        private String ten;

        public void setTen(String ten) {
            this.ten = ten;
        }

        public String getTen() {
            return ten;
        }
    }
    ```

Tính đóng gói giúp tăng tính nhất quán và bảo mật trong lập trình hướng đối tượng bằng cách ẩn thông tin và kiểm soát việc truy cập đến các thành phần của một lớp.

Các access modifier (phạm vi truy cập) trong Java được sử dụng để xác định quyền truy cập của các thành phần (biến, phương thức) của một lớp. Ba access modifier phổ biến là `private`, `protected`, và `public`. Dưới đây là mô tả chi tiết về mỗi loại:

### 1. `private` (Riêng tư):

- **Phạm Vi Truy Cập:** Chỉ có thể truy cập bên trong cùng một lớp.
- **Mục Đích:** Ẩn thông tin và giữ cho các thành phần không thể truy cập từ bên ngoài lớp. Người ta thường sử dụng `private` cho các biến thành viên để bảo vệ dữ liệu.

**Ví dụ:**
```java
public class NhanVien {
    private String ten;  // Biến private chỉ có thể truy cập trong lớp NhanVien
}
```

### 2. `protected` (Bảo vệ):

- **Phạm Vi Truy Cập:** Có thể truy cập từ bên trong cùng một lớp, từ lớp con, và từ cùng package.
- **Mục Đích:** Cho phép truy cập từ các lớp con mà không cần phải là public. Thường được sử dụng trong tình huống kế thừa.

**Ví dụ:**
```java
public class NhanVien {
    protected String ten;  // Biến protected có thể truy cập từ lớp con và cùng package
}
```

### 3. `public` (Công cộng):

- **Phạm Vi Truy Cập:** Có thể truy cập từ mọi nơi, bao gồm cả bên ngoài lớp, package, và các lớp con.
- **Mục Đích:** Cho phép truy cập tự do từ mọi nơi. Các phương thức và biến được khai báo public có thể được sử dụng từ bất kỳ đâu trong chương trình.

**Ví dụ:**
```java
public class NhanVien {
    public String ten;  // Biến public có thể truy cập từ mọi nơi
}
```

### Tổng Kết:

- `private`: Ẩn thông tin và chỉ cho phép truy cập trong lớp.
- `protected`: Cho phép truy cập trong lớp, lớp con và cùng package.
- `public`: Cho phép truy cập từ mọi nơi.

Lựa chọn access modifier phụ thuộc vào mức độ sự ẩn thông tin và mức độ sự quyết định về quyền truy cập. Sử dụng chúng một cách cẩn thận để đảm bảo tính bảo mật và sự linh hoạt trong thiết kế của chương trình.

<hr>

Tính trừu tượng là một trong những tính chất quan trọng của lập trình hướng đối tượng (OOP). Nó đề cập đến khả năng ẩn đi chi tiết cụ thể của một đối tượng và chỉ hiển thị thông tin cần thiết để tương tác với nó. Trong Java, tính trừu tượng có thể được thực hiện thông qua việc sử dụng abstract class và interface.

### Abstract Class (Lớp Trừu Tượng):

- **Đặc Điểm:**
  - Là một lớp mà không thể tạo đối tượng trực tiếp từ nó.
  - Có thể chứa cả phương thức trừu tượng và phương thức có triển khai.
  - Cung cấp một cơ sở cho việc kế thừa.

- **Ví dụ:**
  ```java
  abstract class DongVat {
      // Phương thức trừu tượng
      public abstract void keu();

      // Phương thức có triển khai
      public void diChuyen() {
          System.out.println("Dong vat di chuyen");
      }
  }

  class Meo extends DongVat {
      @Override
      public void keu() {
          System.out.println("Meo keu: Meow");
      }
  }
  ```

### Interface (Giao Diện):

- **Đặc Điểm:**
  - Khai báo các phương thức trừu tượng mà lớp implement nó phải định nghĩa.
  - Một lớp có thể implement nhiều giao diện, giúp đạt được tính đa kế thừa.

- **Ví dụ:**
  ```java
  interface Xe {
      void chay();
      void dung();
  }

  class XeHoi implements Xe {
      @Override
      public void chay() {
          System.out.println("Xe hoi dang chay");
      }

      @Override
      public void dung() {
          System.out.println("Xe hoi da dung");
      }
  }
  ```

### Ưu Điểm của Tính Trừu Tượng:

1. **Ẩn Chi Tiết Cài Đặt:** Cho phép ẩn chi tiết cài đặt bên trong một đối tượng, chỉ hiển thị những gì cần thiết.

2. **Tính Linh Hoạt:** Giúp linh hoạt trong việc thay đổi cài đặt bên trong một lớp mà không ảnh hưởng đến những lớp sử dụng nó.

3. **Đa Kế Thừa (Interface):** Giao diện cho phép một lớp thực hiện nhiều giao diện, tăng tính đa kế thừa.

4. **Giảm Sự Phụ Thuộc:** Đối tượng sử dụng chỉ cần biết về phương thức công cộng của lớp trừu tượng mà không cần biết chi tiết cài đặt bên trong.

Tính trừu tượng giúp tạo ra các lớp và đối tượng linh hoạt, dễ bảo trì và mở rộng trong lập trình hướng đối tượng.