Kiến trúc Dữ liệu và Cơ chế Nền tảng
Java phân loại kiểu dữ liệu thành hai nhóm chính: kiểu nguyên thủy (primitive) và kiểu tham chiếu (reference). Tám kiểu nguyên thủy bao gồm byte, short, int, long, float, double, char và boolean. Mỗi loại đều có lớp bao đóng (wrapper) tương ứng trong gói java.lang để hỗ trợ thao tác đối tượng trong Collections. Kiểu tham chiếu bao gồm lớp, mảng và interface, luôn khởi tạo ngầm định với giá trị null khi khai báo.
Phân biệt toán tử == và phương thức equals()
Toán tử == so sánh địa chỉ bộ nhớ (tham chiếu) giữa hai biến, trong khi equals() được thiết kế để so sánh nội dung logic của đối tượng. Đối với kiểu nguyên thủy, == so sánh trực tiếp giá trị. Khi làm việc với đối tượng, nếu không ghi đè equals(), hành vi mặc định của Object sẽ trở lại so sánh tham chiếu, dẫn đến kết quả sai lệch nếu hai thể hiện khác nhau nhưng chứa cùng dữ liệu.
public class IdentityDemo {
private final String payload;
public IdentityDemo(String data) {
this.payload = data;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
IdentityDemo other = (IdentityDemo) obj;
return payload != null && payload.equals(other.payload);
}
public static void main(String[] args) {
IdentityDemo nodeA = new IdentityDemo("config-v1");
IdentityDemo nodeB = new IdentityDemo("config-v1");
System.out.println(nodeA == nodeB); // false: khác địa chỉ
System.out.println(nodeA.equals(nodeB)); // true: nội dung giống nhau
}
}
Cơ chế Tự động Đóng gói và Bể Hằng Số
Từ Java 5, trình biên dịch hỗ trợ auto-boxing (chuyển nguyên thủy sang wrapper) và auto-unboxing (ngược lại). Cơ chế này tối ưu bộ nhớ thông qua constant pool: các giá trị wrapper nằm trong khoảng -128 đến 127 (đối với Integer) được tái sử dụng từ bể hằng số, giúp so sánh tham chiếu cho kết quả đúng trong giới hạn này. Ngoài khoảng đó, JVM sẽ phân bổ vùng heap mới cho mỗi thể hiện.
Phương thức Cốt lõi của lớp Object
Mọi lớp Java đều kế thừa java.lang.Object. Các phương thức quan trọng bao gồm: hashCode() (xác định vị trí trong cấu trúc băm), equals() (so sánh đẳng thức), toString() (biểu diễn chuỗi), getClass() (kiểm tra runtime type), clone() (sao chép nông), cùng nhóm đồng bộ hóa wait(), notify(), notifyAll() dựa trên monitor lock.
Quản lý Tham chiếu và Thu gom Rác
Trình thu gom rác (GC) phân loại tham chiếu thành bốn cấp độ để linh hoạt kiểm soát vòng đời đối tượng:
- Strong Reference: Mức độ mạnh nhất. GC chỉ thu hồi khi không còn tham chiếu nào trỏ đến đối tượng.
- Soft Reference: Đối tượng chỉ bị thu hồi khi bộ nhớ heap gần cạn. Thường dùng cho cache nhạy cảm với dung lượng.
- Weak Reference: Đối tượng bị thu hồi ngay trong chu kỳ GC tiếp theo bất kể bộ nhớ còn trống hay không. Ứng dụng phổ biến trong
WeakHashMap. - Phantom Reference: Không ảnh hưởng đến vòng đời đối tượng. Kết hợp với
ReferenceQueueđể nhận thông báo khi đối tượng sắp bị giải phóng, hữu ích cho dọn dẹp tài nguyên native.
Hệ sinh thái Collections và Đồng bộ hóa
So sánh Triển khai Danh sách và Bộ đệm Chuỗi
ArrayList dựa trên mảng động, tối ưu cho truy cập ngẫu nhiên nhưng chậm khi chèn/xóa ở đầu. LinkedList dùng cấu trúc danh sách liên kết kép, mạnh ở thao tác thêm/bớt nhưng tốn chi phí duyệt khi tìm kiếm. Vector tương tự ArrayList nhưng dùng từ khóa synchronized cho mọi phương thức, dẫn đến độ trễ cao và ít được sử dụng trong kiến trúc hiện đại.
Về xử lý chuỗi, String là bất biến (immutable). Khi cần thao tác nhiều trên nội dung, StringBuilder (đơn luồng) và StringBuffer (đa luồng, đồng bộ hóa) là lựa chọn phù hợp. Hiệu suất thực thi: StringBuilder > StringBuffer > String.
Phiên bản HashMap qua các thế hệ JDK
JDK 7 triển khai HashMap bằng mảng + danh sách liên kết. Khi va chạm hash xảy ra, các entry được nối thành chuỗi. JDK 8 nâng cấp bằng cách chuyển danh sách liên kết thành cây đỏ-đen (red-black tree) khi số nút trong cùng bucket đạt ngưỡng 8. Cấu trúc này cải thiện độ phức tạp từ O(n) xuống O(log n) trong trường hợp xấu nhất.
Điểm khác biệt then chốt về đồng bộ hóa: Hashtable khóa toàn bộ đối tượng bằng synchronized, gây nghẽn cổ chai. ConcurrentHashMap (JDK 7) dùng Segments chia nhỏ vùng khóa. JDK 8 loại bỏ Segment, thay bằng CAS (Compare-And-Swap) cho thao tác không va chạm và synchronized chỉ khóa đầu链表/bucket cụ thể, đồng thời hỗ trợ resize song song.
public class HashContractDemo {
private final int productId;
private final String category;
public HashContractDemo(int id, String cat) {
this.productId = id;
this.category = cat;
}
@Override
public int hashCode() {
int result = productId;
result = 31 * result + (category != null ? category.hashCode() : 0);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
HashContractDemo that = (HashContractDemo) obj;
return productId == that.productId &&
(category != null ? category.equals(that.category) : that.category == null);
}
}
Việc ghi đè hashCode() và equals() đồng bộ là bắt buộc khi đối tượng được dùng làm key trong HashMap, HashSet hay Hashtable. Nếu vi phạm quy ước, bộ sưu tập sẽ mất khả năng loại bỏ trùng lặp và tra cứu chính xác.
Hệ thống Collection và Tiện ích
Collection là interface gốc cho danh sách đơn (List, Set, Queue). Collections là lớp tiện ích chứa các phương thức tĩnh như sort(), synchronizedList(), unmodifiableMap(). TreeMap sắp xếp key tự nhiên hoặc theo comparator. LinkedHashMap duy trì thứ tự chèn hoặc thứ tự truy cập, hữu ích cho LRU cache.
Cơ chế Ngoại lệ và Giám sát JVM
Luồng thực thi try-catch-finally
Khối finally luôn được thực thi trước khi phương thức hoàn tất, ngay cả khi try hoặc catch chứa lệnh return. Trình ảo JVM sẽ lưu trữ giá trị trả về, thực thi finally, sau đó mới trả kết quả về caller. Ngoại lệ duy nhất ngăn chặn finally là System.exit() hoặc JVM bị dừng đột ngột.
Phân loại Throwable và Cảnh báo Bộ nhớ
Throwable chia làm Error (lỗi hệ thống/JVM không nên catch) và Exception (trạng thái bất thường có thể xử lý). Hai lỗi phổ biến:
- OutOfMemoryError (OOM): Xảy ra khi Heap, Metaspace, Thread stack hoặc Direct buffer cạn kiệt. Nguyên nhân thường do rò rỉ đối tượng, cache không giới hạn hoặc cấu hình JVM thiếu hợp lý.
- StackOverflowError (SOF): Kích hoạt khi khung stack đầy, thường do đệ quy không có điều kiện dừng hoặc vòng lặp hàm quá sâu.
Tư hướng Đối tượng và Mẫu thiết kế
Đặc tính OOP và Đa hình
OAP dựa trên ba trụ cột: Đóng gói (Encapsulation) che giấu trạng thái nội bộ, Kế thừa (Inheritance) tái sử dụng mã, và Đa hình (Polymorphism) cho phép xử lý đối tượng theo kiểu cha nhưng thực thi hành vi con. Đa hình thời gian chạy được JVM giải quyết qua bảng phương thức ảo (vtable), tra cứu địa chỉ phương thức thực tại runtime.
Phân biệt Overload (tải nhiều: cùng tên phương thức, khác danh sách tham số) và Override (ghi đè: cùng chữ ký, trả về tương thích, quyền truy cập không thu hẹp, phát sinh ngoại lệ không mở rộng hơn).
Interface so với Abstract Class
Interface định nghĩa hợp đồng hành vi, chỉ chứa hằng số và phương thức trừu tượng (từ Java 8 hỗ trợ default/static method). Abstract Class cho phép khai báo trường, constructor và phương thức triển khai một phần. Một lớp chỉ kế thừa một abstract class nhưng có thể implement nhiều interface.
Lớp nội bộ Tĩnh và Không tĩnh
static class (nested class) không giữ tham chiếu đến thể hiện lớp bao quanh, chỉ truy cập được thành viên static. non-static inner class gắn liền với đối tượng ngoài, tự động truy cập mọi thành viên của lớp cha, nhưng không thể khai báo thành viên static.
Tính năng Hiện đại và Cơ chế Nâng cao
So sánh IO và NIO
Java IO dựa trên luồng (stream), hoạt động đồng bộ và blocking: một thread chờ đợi cho đến khi đọc/ghi xong. Java NIO (New IO) chuyển sang mô hình kênh (Channel) và đệm (Buffer), hỗ trợ non-blocking và Selector. Selector cho phép một thread giám sát đồng thời nhiều kênh I/O, tối ưu cho hệ thống mạng có hàng nghìn kết nối nhẹ như chat server hoặc websocket gateway.
Reflection và Generics
Reflection cho phép khám phá và gọi phương thức/thuộc tính tại runtime thông qua Class, Method, Field, Constructor. Tuy mạnh mẽ nhưng ảnh hưởng hiệu suất và bypass kiểm tra compile-time. Generics đảm bảo an toàn kiểu tại thời gian biên dịch, nhưng bị xóa bỏ (type erasure) khi chạy, nên không thể dùng instanceof với tham số generic hay tạo mảng generic trực tiếp.
Giải tích XML, JNI và Tách biệt Loáng cắt
DOM xây dựng cây trong RAM, thuận tiện cho tìm kiếm/xóa nhưng tốn bộ nhớ. SAX xử lý theo sự kiện dòng chảy, tiết kiệm tài nguyên nhưng khó thao tác ngược. DOM4J và JDOM là thư viện phổ biến kết hợp ưu điểm cả hai. JNI (Java Native Interface) cầu nối mã Java với C/C++ thông qua khai báo native, biên dịch header, triển khai hàm native và load library. AOP (Aspect-Oriented Programming) tách biệt cross-cutting concerns (log, transaction, security) khỏi logic nghiệp vụ, thường triển khai bằng JDK Dynamic Proxy (yêu cầu interface) hoặc CGLIB/Byte Buddy (kế thừa lớp). Khác với OOP tập trung vào danh từ (thực thể), AOP nhắm vào động từ (chuỗi xử lý), giúp hệ thống giảm ghép nối và tăng khả năng bảo trì.
Tuổi tác JDK và Nguyên tắc Thiết kế
Các phiên bản Java liên tục bổ sung tính năng: JDK 7 hỗ trợ switch string, diamond operator. JDK 8 mang đến Lambda, Stream API, Optional, Functional Interface và thời gian hiện đại. JDK 9 giới thiệu Module System (Jigsaw). JDK 10 bổ sung var cho suy luận kiểu biến cục bộ. Các nguyên tắc SOLID và mẫu thiết kế (Singleton, Factory, Observer, Chain of Responsibility, Adapter) hướng đến mã mở rộng linh hoạt, đóng kín sửa đổi và giảm thiểu phụ thuộc trực tiếp.