Giới thiệu
Vector là một cấu trúc dữ liệu tuyến tính trong hệ sinh thái tập hợp của Java, có cơ chế hoạt động gần như tương tự ArrayList. Một câu hỏi phỏng vấn phổ biến liên quan đến lớp này là: Sự khác biệt giữa ArrayList và Vector là gì?
Câu trả lời thường gặp bao gồm:
Vectoran toàn luồng (thread-safe)- Cơ chế mở rộng dung lượng khác nhau:
ArrayListtăng thêm 50% kích thước hiện tại, trong khiVectortăng gấp đôi
Bài viết này sẽ kiểm chứng các điểm trên thông qua việc phân tích trực tiếp mã nguồn của Vector.
Tính an toàn luồng được đảm bảo như thế nào?
Khi xem xét mã nguồn của Vector, ta thấy rằng tất cả các phương thức thay đổi hoặc truy xuất dữ liệu đều được đánh dấu bằng từ khóa synchronized. Đây chính là lý do khiến Vector được coi là thread-safe.
Dưới đây là một số ví dụ minh họa:
Thêm phần tử
public synchronized boolean add(E item) {
modCount++;
add(item, elementData, elementCount);
return true;
}
Xóa phần tử
public synchronized boolean removeElement(Object target) {
modCount++;
int position = indexOf(target);
if (position >= 0) {
removeElementAt(position);
return true;
}
return false;
}
Cập nhật phần tử
public synchronized E set(int idx, E newValue) {
if (idx >= elementCount)
throw new ArrayIndexOutOfBoundsException(idx);
E oldValue = elementData(idx);
elementData[idx] = newValue;
return oldValue;
}
Lấy phần tử
public synchronized E get(int idx) {
if (idx >= elementCount)
throw new ArrayIndexOutOfBoundsException(idx);
return elementData(idx);
}
Cơ chế mở rộng dung lượng
Hàm mở rộng của Vector được triển khai như sau:
private Object[] grow(int requiredCapacity) {
int currentSize = elementData.length;
int expandedSize = ArraysSupport.newLength(currentSize,
requiredCapacity - currentSize, /* mức tăng tối thiểu */
capacityIncrement > 0 ? capacityIncrement : currentSize
/* mức tăng ưa thích */);
return elementData = Arrays.copyOf(elementData, expandedSize);
}
So với ArrayList, điểm khác biệt nằm ở tham số thứ ba của ArraysSupport.newLength. Nếu không chỉ định capacityIncrement khi khởi tạo Vector, giá trị này mặc định bằng 0. Khi đó, tham số thứ ba sẽ luôn là currentSize, dẫn đến hành vi mở rộng theo cấp số nhân — cụ thể là gấp đôi kích thước hiện tại nếu yêu cầu bộ nhớ mới không vượt quá giới hạn này.
Trường hợp kích thước cần thiết lớn hơn mức tăng mặc định, hệ thống sẽ cấp phát đúng số lượng yêu cầu, nhưng vẫn bị giới hạn bởi hằng số SOFT_MAX_ARRAY_LENGTH.
Mặc dù chi tiết triển khai sâu hơn có thể thú vị, nhưng trong thực tế, Vector hiếm khi được sử dụng do hiệu năng kém hơn so với các lựa chọn thay thế hiện đại.