1. Tính đóng gói trong Java là gì?

Tính đóng gói trong Java – Encapsulation 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.

Ví dụ đối với ô tô thì một số thuộc tính ở bên ngoài như xi nhan, đèn. bánh xe là những thuộc tính công khai (public) người khác xem được. Nhưng đối với các thuộc tính bên trong như đồ đạc trong cốp xe, động cơ,… thì bị giấu đi (private).

Từ đây trong lập trình hướng đối tượng các dữ liệu và phương thức có liên quan với nhau được đóng gói thành các lớp để tiện cho việc quản lý và sử dụng. Tức là mỗi lớp được xây dựng để thực hiện một nhóm chức năng đặc trưng của riêng lớp đó. Ngoài ra, đóng gói còn để che giấu một số thông tin và chi tiết cài đặt nội bộ để bên ngoài không thể nhìn thấy. Tính đóng gói được thể hiện qua cấp độ truy cập trong Java.

2. Đặc điểm của tính đóng gói trong Java

Tính đóng gói trong Java có một số đặc điểm như:

  • Tạo ra cơ chế để ngăn ngừa việc gọi phương thức của lớp này tác động hay truy xuất dữ liệu của đối tượng thuộc về lớp khác.
  • Dữ liệu riêng (khi được khai báo là private) của mỗi đối tượng được bảo vệ khỏi sự truy xuất không hợp lệ từ bên ngoài.
  • Người lập trình có thể dựa vào cơ chế này để ngăn ngừa việc gán giá trị không hợp lệ vào thành phần dữ liệu của mỗi đối tượng.
  • Cho phép thay đổi cấu trúc bên trong của một lớp mà không làm ảnh hưởng đến những lớp bên ngoài có sử dụng lớp đó.

Vì vậy để cài đặt được tính đóng gói ta sẽ làm theo các bước sau:

  • Khai báo các thuộc tính của đối tượng trong lớp là private để các lớp khác không thể truy cập trực tiếp/sửa đổi được.
  • Cung cấp các phương thức getter/setter có phạm vi truy cập là public để truy cập và sửa đổi các giá trị của thuộc tính trong lớp. Phương thức getter là phương thức truy cập vào thuộc tính của đối tượng và trả về các thuộc tính của đối tượng, còn phương thức setter là phương thức truy cập vào thuộc tính của đối tượng và gán giá trị cho các thuộc tính của đối tượng đó.

3. Get và Set trong tính đóng gói

3.1. Phương thức Set

Set được xây dựng để gán hay thay đổi giá trị của biến thể hiện. Cú pháp

bổ_từ_truy_cập void tên_setter(tham_số) {
tên_biến_thể_hiện = tham_số;
}

Trong đó

  • bổ_từ_truy_cập : là Access modifiers nhưng phải khác private
  • tham_số : phải có kiểu tương đương với kiểu của tên_biến_thể_hiện

Ví dụ:

public void setRong(int rong) {
  this.rong = rong;
}
public void setCao(int cao) {
  this.cao = cao;
}

3.2. Phương thức Get

Phương thức Get dùng để lấy giá trị của biến thể hiện. Cú pháp của nó như sau:

bổ_từ_truy_cập kiểu_trả_về tên_getter() {
  return tên_biến_thể_hiện;
}

Trong đó:

  • bổ_từ_truy_cập : là Access modifiers nhưng phải khác private
  • tham_số : phải có kiểu tương đương với kiểu của tên_biến_thể_hiện

Ví dụ:

public void getRong() {
  return rong;
}
public void getCao() {
  return cao;
}

4. Cơ chế che dấu dữ liệu của lớp trong Java

Che dấu dữ liệu – Data hiding là một cách hạn chế quyền truy cập các thuộc tính dữ liệu của lớp bằng cách hạn chế phạm vi truy cập của chúng với các access modifier .

Với chỉ định truy cập là private thì các thuộc tính dữ liệu chỉ có thể truy cập từ các phương thức bên trong lớp nhằm bảo vệ dữ liệu. Các đối tượng khác muốn truy nhập vào dữ liệu riêng tư này phải thông qua các phương thức public .

Đó là các phương thức accessor (getter) trả về giá trị hiện tại của một thuộc tính và mutator (setter) sẽ thay đổi giá trị của một thuộc tính. Định dạng tên của các phương thức này thường là getXsetX với X là tên thuộc tính.

Ví dụ:

class Person {
    //thuộc tính private
    private int age;
    //phương thức getter
    public int getAge() {
      return age;
    }
    //phương thức setter
    public void setAge(int age) {
      this.age = age;
    }
}

class Main {
    public static void main(String[] args) {
        Person p1 = new Person();
        //thay đổi thuộc tính age với setter
        p1.setAge(19);
        //lấy giá trị thuộc tính age với getter
        System.out.println("My age is " + p1.getAge());
    }
}

Kết quả

My age is 19

Trong ví dụ trên, thuộc tính age của lớp Person được khai báo là private và không thể truy cập bên ngoài lớp Person. Để truy cập age bên ngoài lớp Person, chúng ta sử dụng phương thức public getAge()setAge(). Thuộc tính age được khai báo private để hạn chế truy cập từ bên ngoài lớp. Đó là data hiding .

6. Ví dụ cụ thể về tính đóng gói

Mình sẽ đưa ra một ví dụ cụ thể về tính đóng gói trong Java với các file Person.java và file TestPerson.java

File Person.java

package vidu;
 
public class Person {
    // khai báo các thuộc tính của đối tượng là private
    private String cmnd;
    private String hoTen;
     
    // tạo các phương thức getter/setter
    // 2 phương thức getCmnd() và getHoTen() là phương thức getter
    // dùng để trả về số chứng minh nhân dân và họ tên của đối tượng
    // và kiểu trả về của hai phương thức này tương ứng với kiểu dữ liệu của thuộc tính
    // 2 phương thức setCmnd() và setHoTen() là phương thức setter
    // dùng để gán giá trị cho thuộc tính chứng minh nhân dân và họ tên của đối tượng
    // trong đó tham số truyền vào của 2 phương thức này được gọi là tham số (biến cục bộ)
    // và có kiểu dữ liệu tương ứng với kiểu dữ liệu của thuộc tính (biến đối tượng)
    public String getCmnd() {
        return cmnd;
    }
     
    // this là từ khóa có ý nghĩa là một tham chiếu đặc biệt 
    // chiếu tới đối tượng chủ của phương thức hiện hành
    // this có thể được dùng để truy cập biến đối tượng (instance variable)
    // hoặc gọi phương thức đối với đối tượng hiện hành. 
    // Thông thường, công dụng này của this chỉ có ích
    // khi tên biến đối tượng bị trùng với tham số (biến cục bộ - local variable) của phương thức 
    public void setCmnd(String cmnd) {
        this.cmnd = cmnd;
    }
    public String getHoTen() {
        return hoTen;
    }
    public void setHoTen(String hoTen) {
        this.hoTen = hoTen;
    }
     
}

File TestPerson.java

package vidu;
 
public class TestPerson {
 
    public static void main(String[] args) {
        Person person = new Person();
         
        // gán giá trị họ tên cho đối tượng person vừa tạo thông qua setHoTen() 
        // và gán số chứng minh nhân dân thông qua setCmnd()
        person.setHoTen("Thành Nguyễn");   
        person.setCmnd("0060108102222");
         
        // truy cập đến tên của đối tượng person thông qua phương thức getHoten()
        // và số chứng minh nhân dân thông qua phương thức getCmnd()
        System.out.println("Tên: " + person.getHoTen() + ", số cmnd: " + person.getCmnd());
    }
 
}

Kết quả

Tên: Thành Nguyễn, số cmnd: 0060108102222