Kiểm Soát Truy Cập Trong Java: Phạm Vi Hoạt Động Của Public, Protected, Default Và Private

Trong lập trình Java, việc quản lý phạm vi truy cập của các thành phần trong lớp là yếu tố then chốt để đảm bảo tính đóng gói và bảo mật mã nguồn. Java cung cấp bốn bổ từ truy cập giúp lập trình viên xác định rõ ràng mức độ hiển thị của thuộc tính, phương thức và lớp.

Phân Loại Và Mức Độ Hiển Thị

Mỗi bổ từ sẽ quy định một ranh giới truy cập khác nhau:

  • public: Mức công khai cao nhất. Thành phần có thể được gọi từ bất kỳ lớp nào trong toàn bộ dự án.
  • protected: Mức bảo vệ. Cho phép truy cập trong cùng gói (package) và các lớp con kế thừa, ngay cả khi lớp con nằm ở gói khác.
  • default (mặc định): Không sử dụng từ khóa nào. Thành phần chỉ khả dụng cho các lớp nằm trong cùng một gói.
  • private: Mức riêng tư. Chỉ lớp chứa thành phần đó mới được phép truy cập. Mọi lớp khác đều không thể nhìn thấy.

Minh Họa Qua Mã Nguồn

Để nắm vững cơ chế hoạt động, chúng ta sẽ phân tích hành vi truy cập thông qua các tình huống thực tế dưới đây.

1. Truy cập nội bộ trong cùng một lớp

Khi các phương thức và biến nằm chung một lớp, mọi rào cản truy cập đều bị gỡ bỏ. Lớp đó có toàn quyền thao tác với tất cả thành viên của chính nó.

package com.example.core;

public class DataContainer {
    public String publicField = "Công khai";
    protected String protectedField = "Bảo vệ";
    String defaultField = "Mặc định";
    private String privateField = "Riêng tư";

    public void displayAll() {
        // Trong cùng lớp, mọi bổ từ đều hoạt động bình thường
        System.out.println(publicField);
        System.out.println(protectedField);
        System.out.println(defaultField);
        System.out.println(privateField);
    }
}

2. Tương tác giữa các lớp cùng gói

Các lớp nằm chung thư mục gói có thể chia sẻ dữ liệu ở mức public, protecteddefault. Tuy nhiên, thành phần private vẫn bị ẩn đi.

package com.example.core;

public class LocalClient {
    public void fetchData() {
        DataContainer container = new DataContainer();
        
        // Hợp lệ: cùng gói nên thấy được public, protected và default
        System.out.println(container.publicField);
        System.out.println(container.protectedField);
        System.out.println(container.defaultField);
        
        // Lỗi biên dịch: privateField không thể truy cập từ lớp khác
        // System.out.println(container.privateField); 
    }
}

3. Gọi từ lớp nằm ở gói khác

Khi vượt ra khỏi ranh giới gói, chỉ những thành phần được đánh dấu public mới có thể được sử dụng. Các mức còn lại sẽ bị trình biên dịch chặn lại.

package com.example.external;

import com.example.core.DataContainer;

public class RemoteClient {
    public static void main(String[] args) {
        DataContainer obj = new DataContainer();
        
        // Chỉ publicField là khả dụng
        System.out.println(obj.publicField);
        
        // Các dòng dưới đây sẽ gây lỗi biên dịch:
        // obj.protectedField; // Không cùng gói, không phải lớp con
        // obj.defaultField;   // Khác gói
        // obj.privateField;   // Hoàn toàn riêng tư
    }
}

Cấu Trúc Thư Mục Dự Án

Để các ví dụ trên hoạt động chính xác, cấu trúc thư mục cần được tổ chức phân tách rõ ràng theo gói:

src/
├── com/
│   └── example/
│       ├── core/
│       │   ├── DataContainer.java
│       │   └── LocalClient.java
│       └── external/
│           └── RemoteClient.java

Nguyên Tắc Áp Dụng Thực Tế

  • Bổ từ truy cập có thể áp dụng cho biến thành viên, phương thức, lớp nội bộ và lớp ngoài cùng.
  • Đối với lớp ngoài cùng (top-level class), Java chỉ cho phép dùng public hoặc default. Không thể khai báo lớp chính là private hay protected.
  • Luôn tuân thủ nguyên tắc đóng gói: ưu tiên private cho dữ liệu nội bộ, cung cấp phương thức public (getter/setter) để kiểm soát việc đọc/ghi từ bên ngoài.
  • Sử dụng protected khi thiết kế thư viện cần cho phép lớp con ghi đè hoặc mở rộng logic, nhưng vẫn muốn ẩn chi tiết cài đặt với người dùng cuối.

Thẻ: Java access-modifiers oop encapsulation java-packages

Đăng vào ngày 3 tháng 9 lúc 11:21