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, protected và default. 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
publichoặcdefault. Không thể khai báo lớp chính làprivatehayprotected. - Luôn tuân thủ nguyên tắc đóng gói: ưu tiên
privatecho dữ liệu nội bộ, cung cấp phương thứcpublic(getter/setter) để kiểm soát việc đọc/ghi từ bên ngoài. - Sử dụng
protectedkhi 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.