
Public Modifier: 'Cánh Cửa Mở Toang' Trong Thế Giới Code Của Gen Z
Chào các bạn Gen Z mê code, đây là Creyt, giảng viên lập trình của các bạn! Hôm nay, chúng ta sẽ cùng “bóc tách” một khái niệm tưởng chừng đơn giản nhưng lại cực kỳ quan trọng trong Java OOP: public modifier. Hãy tưởng tượng nó như một "cánh cửa mở toang" trong ngôi nhà code của bạn. Nghe có vẻ dễ dãi đúng không? Nhưng tin Creyt đi, đôi khi sự dễ dãi này lại là cả một nghệ thuật đấy!
1. public là gì và để làm gì? (Theo hướng Gen Z)
Trong lập trình Java, public là một trong bốn access modifiers (bộ điều chỉnh quyền truy cập), và nó chính là "ông hoàng của sự công khai". Khi bạn gắn public cho một class, một method, một field (biến), hay một constructor, bạn đang tuyên bố với cả thế giới code rằng: "Này, cái này của tôi đây, ai cũng có thể thấy, ai cũng có thể dùng!"
Để làm gì ư? Đơn giản là để các thành phần đó có thể được truy cập từ bất kỳ đâu trong project của bạn, thậm chí từ các package khác. Giống như bạn đăng một story công khai trên Instagram hay TikTok vậy – ai cũng xem được, ai cũng tương tác được. Không cần follow, không cần xin phép, chỉ cần biết nó tồn tại là dùng được luôn!
2. Cốt lõi vấn đề: public hoạt động như thế nào trong Java OOP?
public mang lại mức độ truy cập rộng nhất. Nó là cầu nối để các đối tượng "trò chuyện" với nhau. Hãy xem nó áp dụng cho những thành phần nào nhé:
- Class: Khi một
classlàpublic, nó có thể được truy cập và sử dụng từ bất kỳ class nào khác, bất kể chúng nằm trong package nào đi chăng nữa. Đây là kiểu mặc định cho các class chính trong file Java của bạn. - Method: Một
methodpubliccó thể được gọi từ bất cứ đâu. Đây là cách chính để các đối tượng tương tác và thực hiện các hành động. - Field (Biến): Một
fieldpubliccó thể được truy cập và thay đổi giá trị trực tiếp từ bất kỳ đâu. Nhưng khoan! Đây thường là một "red flag" trong OOP, và Creyt sẽ giải thích sau. - Constructor: Một
constructorpubliccho phép bạn tạo ra các instance (đối tượng) của class từ bất kỳ đâu.
3. Code Ví Dụ Minh Hoạ: "Mở cửa" code cho cả thế giới
Để dễ hình dung, chúng ta sẽ tạo hai package và xem cách public kết nối chúng nhé. Hãy tưởng tượng com.creyt.core là nơi chứa "linh hồn" của các đối tượng, và com.creyt.app là nơi chúng ta "triệu hồi" và sử dụng chúng.
// Package: com.creyt.core
package com.creyt.core;
public class SinhVien {
// Field public: Dễ dàng truy cập từ bên ngoài, nhưng thường không khuyến khích trực tiếp
public String maSinhVien;
// Field private: Chỉ truy cập được trong chính class SinhVien này
private String tenSinhVien;
// Constructor public: Cho phép tạo đối tượng SinhVien từ bất kỳ đâu
public SinhVien(String maSinhVien, String tenSinhVien) {
this.maSinhVien = maSinhVien;
this.tenSinhVien = tenSinhVien;
System.out.println("Sinh viên " + tenSinhVien + " (Mã: " + maSinhVien + ") đã được tạo.");
}
// Method public: Mọi đối tượng khác có thể gọi method này để sinh viên học bài
public void hocBai() {
System.out.println(tenSinhVien + " đang học bài rất chăm chỉ.");
}
// Method public (Getter): Cung cấp cách công khai để đọc giá trị của 'tenSinhVien' (vì nó là private)
public String getTenSinhVien() {
return tenSinhVien;
}
// Method public (Setter): Cung cấp cách công khai để thay đổi giá trị của 'tenSinhVien'
// Chúng ta có thể thêm logic kiểm tra ở đây trước khi thay đổi (tính đóng gói)
public void setTenSinhVien(String tenSinhVienMoi) {
if (tenSinhVienMoi != null && !tenSinhVienMoi.trim().isEmpty()) {
this.tenSinhVien = tenSinhVienMoi;
System.out.println("Tên sinh viên đã được cập nhật thành: " + tenSinhVien);
} else {
System.out.println("Tên sinh viên không hợp lệ. Vui lòng thử lại.");
}
}
}
// Package: com.creyt.app
package com.creyt.app;
// Import class SinhVien từ package khác nhờ nó là public
import com.creyt.core.SinhVien;
public class TruongHoc {
public static void main(String[] args) {
System.out.println("\n--- Demo Public Modifier ---");
// 1. Tạo đối tượng SinhVien từ package khác (nhờ constructor public)
SinhVien sv1 = new SinhVien("SV001", "Nguyễn Văn A");
// 2. Truy cập field public trực tiếp: maSinhVien
// Điều này là CÓ THỂ, nhưng thường KHÔNG KHUYẾN KHÍCH trong thực tế vì phá vỡ tính đóng gói.
System.out.println("Mã sinh viên (public field): " + sv1.maSinhVien);
sv1.maSinhVien = "SV001_NEW"; // Thay đổi trực tiếp field public
System.out.println("Mã sinh viên sau khi đổi: " + sv1.maSinhVien);
// 3. Gọi method public: hocBai()
sv1.hocBai();
// 4. Cố gắng truy cập field private: tenSinhVien (sẽ gây lỗi compile)
// System.out.println(sv1.tenSinhVien); // LỖI: tenSinhVien has private access in com.creyt.core.SinhVien
// 5. Truy cập field private thông qua public getter method
System.out.println("Tên sinh viên (qua getter): " + sv1.getTenSinhVien());
// 6. Thay đổi field private thông qua public setter method
sv1.setTenSinhVien("Trần Thị B");
System.out.println("Tên sinh viên sau khi đổi (qua setter): " + sv1.getTenSinhVien());
sv1.setTenSinhVien(" "); // Thử với input không hợp lệ
System.out.println("Tên sinh viên hiện tại: " + sv1.getTenSinhVien());
// Tạo một đối tượng sinh viên khác để thấy tính độc lập của các đối tượng
System.out.println("\n--- Tạo thêm sinh viên ---");
SinhVien sv2 = new SinhVien("SV002", "Lê Thị C");
sv2.hocBai();
}
}

4. Mẹo hay từ Creyt: Dùng public sao cho "chuẩn gu" Gen Z
- "Cẩn thận với cửa mở toang": Mặc dù
publictiện lợi, nhưng việc biến mọi thứ thànhpubliclà một "red flag" trong lập trình hướng đối tượng. Nó phá vỡ tính đóng gói (encapsulation) – một trong những trụ cột của OOP. Hãy coi chừng, vì code của bạn có thể dễ bị "nhúng chàm" bởi những thay đổi không kiểm soát! - Encapsulation là "fashion statement": Hãy coi các thuộc tính (fields) là những thứ riêng tư (private) của đối tượng. Nếu muốn truy cập hay thay đổi, hãy dùng các "cánh cửa nhỏ" có kiểm soát (public getter/setter methods). Điều này giúp bạn kiểm soát dữ liệu, đảm bảo tính hợp lệ của nó trước khi cho phép thay đổi. Ví dụ như
setTenSinhVienở trên, nó kiểm tra giá trị đầu vào. publiccho interfaces và abstract methods: Các thành phần này luôn luôn làpublic(mặc định) vì chúng định nghĩa hợp đồng cho các lớp khác phải implement. Chúng là những lời hứa mà các class con phải thực hiện.public static finalcho hằng số: Khi bạn có một giá trị không đổi mà mọi người cần biết và sử dụng (ví dụ:Math.PItrong thư viện Java), hãy dùngpublic static final. Đây là trường hợp hiếm hoi màpublicfield được khuyến khích.
5. Học thuật Harvard, dễ hiểu tuyệt đối: Triết lý đằng sau public
Từ góc độ học thuật, public đóng vai trò then chốt trong việc định hình giao diện (interface) công khai của một đối tượng. Nó là cầu nối để các đối tượng khác có thể "trò chuyện" và tương tác mà không cần biết quá nhiều chi tiết bên trong (nguyên lý information hiding – giấu thông tin). Tức là, bạn chỉ cần biết SinhVien có thể hocBai() và có getTenSinhVien(), chứ không cần quan tâm hocBai() được triển khai như thế nào hay tenSinhVien được lưu trữ ra sao.
Nói cách khác, các thành phần public chính là các điểm tương tác trong API (Application Programming Interface) mà bạn thiết kế cho chính các class của mình. Một API tốt sẽ có các điểm công khai rõ ràng, dễ hiểu và an toàn để sử dụng.
6. Ứng dụng thực tế: public ở khắp mọi nơi!
Bạn dùng public mỗi ngày mà không hề hay biết, Creyt thề!
- Thư viện/Framework Java: Khi bạn sử dụng
java.util.ArrayListhayjavax.servlet.http.HttpServlet, bạn đang gọi cácpublicmethods của chúng. Bạn không cần biết bên trongArrayListlưu dữ liệu thế nào, chỉ cần biết các methodadd(),get(),size()làpublicvà bạn có thể dùng. - API Web (REST API): Các endpoint mà bạn gọi từ frontend (ví dụ:
/users,/productsđể lấy danh sách người dùng hoặc sản phẩm) có thể coi là các "public methods" của server-side code. Chúng được thiết kế để lộ ra cho bên ngoài sử dụng một cách có kiểm soát. - Game Development: Các chức năng như
player.move(),enemy.attack()thường làpublicđể các phần khác của game engine có thể điều khiển hoặc tương tác với các đối tượng trong game.
7. Thử nghiệm và Hướng dẫn: Khi nào nên "mở cửa" và khi nào nên "khép hờ"?
Creyt đã từng trải nghiệm: Hồi mới vào nghề, Creyt cũng hay "vô tư" đặt public cho tất cả mọi thứ vì thấy code chạy được. Nhưng rồi gặp phải bug "trời ơi đất hỡi" khi một phần code ở xa lắc xa lơ thay đổi giá trị của một biến quan trọng mà không ai hay biết, dẫn đến những hành vi khó lường. Từ đó mới thấm thía bài học về tính đóng gói và tầm quan trọng của việc kiểm soát quyền truy cập.
**Khi nào nên dùng public?
**
- Class chính: Các class mà bạn muốn các class khác có thể tạo đối tượng hoặc kế thừa từ chúng.
- Constructor: Để cho phép tạo đối tượng của class đó.
- Method giao diện (API): Các method mà bạn muốn là cách chính để tương tác với đối tượng của mình (như
hocBai(),getTenSinhVien(),setTenSinhVien()). Đây là các "cổng giao tiếp" chính thức. - Hằng số:
public static finalvariables cho các giá trị không đổi mà toàn bộ ứng dụng cần sử dụng.
**Khi nào nên hạn chế dùng public?
**
- Fields (biến thành viên): Hầu hết các trường hợp, hãy giữ chúng là
privatevà cung cấppublicgetters/setters (nếu cần). Điều này giúp bạn kiểm soát dữ liệu, thêm logic kiểm tra và bảo vệ trạng thái nội bộ của đối tượng. - Methods nội bộ: Các method chỉ dùng để hỗ trợ các method
publickhác trong cùng một class thì nên làprivatehoặcprotected. Đừng "khoe" những chi tiết triển khai nội bộ ra bên ngoài không cần thiết.
Nhớ nhé, public như một con dao hai lưỡi: tiện lợi nhưng cũng tiềm ẩn rủi ro nếu không dùng đúng cách. Hãy là những lập trình viên Gen Z thông thái, biết khi nào nên "mở cửa" và khi nào nên "khép hờ" để code của mình vừa linh hoạt, vừa an toàn!
Thuộc Series: Java – OOP
Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!