Class Hashtable<K,V>

Hashtable<K,V> là một lớp băm cổ điển trong Java, được sử dụng để lưu trữ các cặp khóa-giá trị nhưng hiện tại đã dần bị thay thế bởi các lớp khác như HashMap và ConcurrentHashMap trong hầu hết các trường hợp sử dụng. Nó kế thừa từ lớp Dictionary<K,V> và triển khai các giao diện Map<K,V>, Cloneable, và Serializable.

Cấu trúc: Hashtable thực chất là một mảng (array) của các danh sách (list), thường được gọi là các "xô" (bucket). Mỗi xô này có thể chứa nhiều phần tử.

Cấu trúc của một phần tử trong Hashtable

Hashtable là một lớp trong Java Collection Framework, tương tự như HashMap nhưng được đồng bộ hóa (synchronized) để sử dụng trong môi trường đa luồng. Mặc dù có sự khác biệt về tính đồng bộ, nhưng về cơ bản cấu trúc của một phần tử trong Hashtable và HashMap là tương tự nhau:

↳ Bucket (Xô): Là vị trí trong bảng băm (hash table) mà phần tử sẽ được lưu trữ. Mỗi bucket có thể chứa nhiều phần tử trong trường hợp xảy ra xung đột băm (hash collision). Trong Hashtable, mỗi bucket thường là một danh sách liên kết (linked list) chứa các phần tử có cùng hash code.

↳ Entry (Cặp khóa-giá trị): Mỗi phần tử trong Hashtable được lưu trữ dưới dạng một đối tượng Entry (còn gọi là Node). Entry chứa Key, Value, và con trỏ next trỏ đến phần tử tiếp theo trong danh sách liên kết của bucket (nếu có). Entry cũng chứa giá trị hash code được tính toán từ Key.

↳ int hash: Giá trị băm (hash value) của khóa, được sử dụng để xác định vị trí của phần tử trong bảng băm.

↳ Key (Khóa): Đây là giá trị duy nhất được sử dụng để xác định vị trí của phần tử trong Hashtable. Key không thể là null trong Hashtable. Key phải là duy nhất trong Hashtable. Key được sử dụng để tính toán giá trị băm (hash value), giúp xác định bucket mà phần tử sẽ được lưu trữ.

↳ Value (Giá trị): Đây là giá trị được liên kết với một Key cụ thể. Value có thể là null trong Hashtable, nhưng thường là giá trị mà bạn muốn lưu trữ và truy cập thông qua Key.

↳ Node<K,V> next: Con trỏ trỏ đến phần tử tiếp theo trong bucket, nếu có (các phần tử trong cùng một bucket tạo thành một danh sách liên kết).

Yêu cầu: Phải ghi đè phương thức hashCode() để đảm bảo phân phối đều trong các bucket. Cũng phải ghi đè phương thức equals() để so sánh các khóa.

Mô tả các phần tử trong Hashtable - minh họa
Mô tả các phần tử trong Hashtable.

Cách thức hoạt động của Hashtable

↳ Khi bạn thêm một phần tử vào Hashtable, một hàm băm (hash function) sẽ được áp dụng lên key của phần tử đó để tạo ra một giá trị băm (hash code).s

↳ Giá trị băm này sẽ được sử dụng làm chỉ số để xác định xô mà phần tử sẽ được đặt vào trong mảng.

↳ Nếu nhiều phần tử có cùng giá trị băm, chúng sẽ được đặt vào cùng một xô. Đây được gọi là "collision" (xung đột).

↳ Để giải quyết xung đột, các danh sách bên trong mỗi xô thường được sử dụng (ví dụ như danh sách liên kết).

Đặc điểm nổi bậc của lớp Hashtable<K,V>

↳ Không cho phép null: Hashtable không cho phép sử dụng null cho cả khóa và giá trị. Điều này khác biệt so với HashMap, nơi mà cả khóa và giá trị đều có thể là null.

↳ Đồng bộ hóa: Hashtable là một lớp đồng bộ hóa, có nghĩa là nó an toàn khi sử dụng trong các môi trường đa luồng mà không cần phải đồng bộ hóa thêm. Tuy nhiên, nếu không cần thiết sử dụng tính năng này, HashMap thường được khuyến khích sử dụng thay vì Hashtable do hiệu suất cao hơn.

↳ Khóa và giá trị không trùng lặp: Giống như tất cả các lớp Map, Hashtable không cho phép hai khóa giống nhau. Mỗi khóa chỉ có thể ánh xạ đến một giá trị duy nhất.

↳ Yêu cầu hashCode và equals: Để lưu trữ và truy xuất các đối tượng từ Hashtable, các đối tượng được sử dụng làm khóa phải triển khai phương thức hashCode và equals để đảm bảo rằng chúng có thể được ánh xạ đúng cách.

↳ Các tham số về hiệu suất: Hashtable có hai tham số ảnh hưởng đến hiệu suất của nó:

↳ Capacity (Sức chứa ban đầu): Là số lượng "bucket" (vị trí trong bảng băm) trong Hashtable.

↳ Load factor (Hệ số tải): Là thước đo độ đầy của Hashtable trước khi nó tăng dung lượng tự động. Thường hệ số tải mặc định là 0.75.

↳ Fail-fast Iterator: Các bộ lặp (iterator) của Hashtable là "fail-fast", nghĩa là chúng sẽ ném ra ngoại lệ ConcurrentModificationException nếu Hashtable bị thay đổi cấu trúc sau khi iterator được tạo ra. Điều này giúp tránh được các hành vi không mong muốn hoặc không xác định.

↳ Thay thế bởi ConcurrentHashMap: Trong các môi trường cần sự đồng bộ cao và thực thi đồng thời, ConcurrentHashMap là lựa chọn tốt hơn so với Hashtable do nó cung cấp hiệu suất cao hơn và các tính năng đồng thời tối ưu hơn.

Khai báo Class Hashtable<K,V> trong Java

Để sử dụng Class Hashtable<K,V>, bạn cần import gói java.util vào đầu file Java của mình.

Cú pháp câu lệnh import:

Cú pháp

import java.util.Hashtable;

Cú pháp khai báo Class Hashtable<K,V>:

Cú pháp

public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, Serializable

Dưới đây là giải thích chi tiết về cú pháp khai báo này:

↳ public: Lớp Hashtable là công khai, nghĩa là nó có thể được truy cập từ bất kỳ đâu trong chương trình.

↳ class: Từ khóa để khai báo một lớp trong Java.

↳ Hashtable<K,V>: Tên lớp là Hashtable có sử dụng generic với hai tham số kiểu (K cho khóa và V cho giá trị). Bạn có thể tạo một đối tượng Hashtable với bất kỳ loại khóa và giá trị nào (như Hashtable<String, Integer>).

↳ extends Dictionary<K,V>: Hashtable kế thừa lớp Dictionary, một lớp trừu tượng trong Java đại diện cho một tập hợp các cặp khóa-giá trị. Dictionary là tổ tiên của Map nhưng hiện nay thường ít được sử dụng so với Map.

↳ implements Map<K,V>: Hashtable triển khai giao diện Map, nghĩa là nó có thể hoạt động như một bản đồ, cho phép lưu trữ các cặp khóa-giá trị và cung cấp các phương thức để truy xuất, thêm, sửa và xóa các cặp khóa-giá trị.

↳ implements Cloneable: Hashtable triển khai giao diện Cloneable, nghĩa là các đối tượng của lớp này có thể được sao chép (tạo ra một đối tượng khác giống hệt).

↳ implements Serializable: Hashtable triển khai giao diện Serializable, nghĩa là các đối tượng của lớp này có thể được tuần tự hóa, tức là có thể chuyển đổi thành một chuỗi byte để lưu trữ hoặc truyền qua mạng.

Các constructor của lớp Hashtable

Lớp Hashtable cung cấp các constructor để tạo một bản đồ đồng bộ với các tùy chọn về dung lượng ban đầu và hệ số tải. Bạn có thể tạo một bản đồ rỗng hoặc một bản đồ chứa các mục nhập từ một bản đồ khác. Dưới đây là bốn constructor của lớp Hashtable:

↳ Hashtable(): Tạo một Hashtable rỗng với dung lượng ban đầu mặc định (11) và hệ số tải mặc định (0.75).

↳ Hashtable(int initialCapacity): Tạo một Hashtable rỗng với dung lượng ban đầu được chỉ định và hệ số tải mặc định (0.75).

↳ Hashtable(int initialCapacity, float loadFactor): Tạo một Hashtable rỗng với dung lượng ban đầu được chỉ định và hệ số tải được chỉ định.

↳ Hashtable(Map<? extends K, ? extends V> t): Tạo một Hashtable mới với các ánh xạ giống như Map được chỉ định.

Ví dụ

Hashtable<String, Integer> table = new Hashtable<>();

// Tạo một Hashtable với dung lượng ban đầu là 32
Hashtable<String, Integer> table2 = new Hashtable<>(32);

// Tạo một Hashtable với dung lượng ban đầu là 16 và hệ số tải là 0.8
Hashtable<String, Integer> table3 = new Hashtable<>(16, 0.8);

// Tạo một Hashtable từ một bản đồ khác
Map<String, Integer> otherMap = new HashMap<>();
otherMap.put("apple", 5);
otherMap.put("banana", 3);
Hashtable<String, Integer> table4 = new Hashtable<>(otherMap);

Lưu ý:

↳ Hashtable là một bản đồ đồng bộ (thread-safe) sử dụng bảng băm để lưu trữ các mục nhập.

↳ Dung lượng ban đầu và hệ số tải được sử dụng để điều chỉnh kích thước của bảng băm và khi nào bảng băm cần được tăng kích thước.

Các phương thức chính trong lớp Hashtable

Lớp Hashtable cung cấp các phương thức để thao tác với các cặp khóa-giá trị trong một Hashtable, bao gồm thêm, xóa, lấy, kiểm tra và duyệt qua các mục nhập. Dưới đây là danh sách tất cả các phương thức của interface Hashtable<K,V> trong Java:

↳ void clear(): Xóa tất cả các ánh xạ khỏi bản đồ này.

↳ Object clone(): Tạo một bản sao nông của Hashtable này.

↳ compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction): Thử tính toán một ánh xạ cho khóa đã cho và giá trị được ánh xạ hiện tại của nó (hoặc null nếu không có ánh xạ hiện tại).

↳ computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction): Nếu khóa đã cho chưa được liên kết với một giá trị (hoặc được ánh xạ đến null), thử tính toán giá trị của nó bằng cách sử dụng hàm ánh xạ đã cho và nhập nó vào bản đồ này trừ khi null.

↳ computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction): Nếu giá trị cho khóa đã cho có mặt và không null, thử tính toán một ánh xạ mới dựa trên khóa và giá trị được ánh xạ hiện tại của nó.

↳ boolean contains(Object value): Kiểm tra xem một số khóa có ánh xạ đến giá trị đã cho trong Hashtable này hay không.

↳ boolean containsKey(Object key): Kiểm tra xem đối tượng đã cho có phải là một khóa trong Hashtable này hay không.

↳ boolean containsValue(Object value): Trả về true nếu Hashtable này ánh xạ một hoặc nhiều khóa đến giá trị này.

↳ Enumeration<V> elements(): Trả về một enumeration của các giá trị trong Hashtable này.

↳ Set<Map.Entry<K,V>> entrySet(): Trả về một view Set của các ánh xạ có trong bản đồ này.

↳ boolean equals(Object o): So sánh đối tượng đã cho với bản đồ này để kiểm tra xem chúng có bằng nhau hay không, theo định nghĩa trong giao diện Map.

↳ void forEach(BiConsumer<? super K, ? super V> action): Thực hiện hành động đã cho cho mỗi mục nhập trong bản đồ này cho đến khi tất cả các mục nhập đã được xử lý hoặc hành động ném ra một ngoại lệ.

↳ get(Object key): Trả về giá trị mà khóa đã cho được ánh xạ đến, hoặc null nếu bản đồ này không chứa ánh xạ nào cho khóa.

↳ getOrDefault(Object key, V defaultValue): Trả về giá trị mà khóa đã cho được ánh xạ đến, hoặc defaultValue nếu bản đồ này không chứa ánh xạ nào cho khóa.

↳ int hashCode(): Trả về giá trị mã băm cho bản đồ này theo định nghĩa trong giao diện Map.

↳ boolean isEmpty(): Kiểm tra xem Hashtable này có chứa bất kỳ khóa nào hay không.

↳ Enumeration<K> keys(): Trả về một enumeration của các khóa trong Hashtable này.

↳ Set<K> keySet(): Trả về một view Set của các khóa có trong bản đồ này.

↳ merge(K key, V value, BiFunction<? super K, ? super V, ? extends V> remappingFunction): Nếu khóa đã cho chưa được liên kết với một giá trị hoặc được ánh xạ đến null, liên kết nó với giá trị không null đã cho.

↳ put(K key, V value): Ánh xạ khóa đã cho đến giá trị đã cho trong Hashtable này.

↳ void putAll(Map<? extends K, ? extends V> t): Sao chép tất cả các ánh xạ từ bản đồ đã cho vào Hashtable này.

↳ putIfAbsent(K key, V value): Nếu khóa đã cho chưa được liên kết với một giá trị (hoặc được ánh xạ đến null), liên kết nó với giá trị đã cho và trả về null, nếu không thì trả về giá trị hiện tại.

↳ protected void rehash(): Tăng dung lượng và sắp xếp lại nội bộ Hashtable này, để chứa và truy cập các mục nhập của nó hiệu quả hơn.

↳ remove(Object key): Xóa khóa (và giá trị tương ứng của nó) khỏi Hashtable này.

↳ Boolean remove(Object key, Object value): Xóa mục nhập cho khóa đã cho chỉ khi nó hiện đang được ánh xạ đến giá trị đã cho.

↳ replace(K key, V value): Thay thế mục nhập cho khóa đã cho chỉ khi nó hiện đang được ánh xạ đến một số giá trị.

↳ boolean replace(K key, V oldValue, V newValue): Thay thế mục nhập cho khóa đã cho chỉ khi nó hiện đang được ánh xạ đến giá trị đã cho.

↳ void replaceAll(BiFunction<? super K, ? super V, ? extends V> function): Thay thế giá trị của mỗi mục nhập bằng kết quả của việc gọi hàm đã cho trên mục nhập đó cho đến khi tất cả các mục nhập đã được xử lý hoặc hàm ném ra một ngoại lệ.

↳ int size(): Trả về số lượng khóa trong Hashtable này.

↳ String toString(): Trả về một chuỗi biểu diễn đối tượng Hashtable này dưới dạng một tập hợp các mục nhập, được bao quanh bởi dấu ngoặc nhọn và được phân tách bởi các ký tự ASCII ", " (dấu phẩy và khoảng trắng).

↳ Collection<V>values(): Trả về một view Collection của các giá trị có trong bản đồ này.

Ví dụ về cách sử dụng các phương thức put(), remove(), replace(), merge() và putIfAbsent()

Dưới đây là ví dụ về việc sử dụng các phương thức put(), remove(), replace(), merge() và putIfAbsent() trong một lớp Java để thêm, sửa, và xóa phần tử trong Hashtable:

Ví dụ: Example.java

import java.util.Hashtable;

public class Example {
    public static void main(String[] args) {
        // Tạo một đối tượng Hashtable
        Hashtable<String, Integer> hashtable = new Hashtable<>();

        // Thêm cặp khóa-giá trị vào Hashtable
        hashtable.put("A", 5);
        hashtable.put("B", 10);
        hashtable.put("C", 15);
        System.out.println("Hashtable ban đầu: " + hashtable);

        // Sửa giá trị của một khóa đã tồn tại
        hashtable.put("A", 5); // Giá trị cũ bị ghi đè
        System.out.println("Sau khi cập nhật tuổi của A: " + hashtable);

        // Xóa một cặp khóa-giá trị theo khóa
        hashtable.remove("B");
        System.out.println("Sau khi xóa B: " + hashtable);

        // Thay thế giá trị của một khóa đã tồn tại
        hashtable.replace("C", 10);
        System.out.println("Sau khi thay thế tuổi của C: " + hashtable);

        // Thêm hoặc cập nhật một giá trị dựa trên hàm tính toán
        hashtable.merge("C", 4, (oldValue, newValue) -> oldValue + newValue);
        System.out.println("Sau khi thay thế tuổi của C: " + hashtable);

        // Chỉ thêm cặp khóa-giá trị nếu khóa chưa tồn tại
        hashtable.putIfAbsent("D", 20);
        System.out.println("Sau khi sử dụng putIfAbsent cho D: " + hashtable);
    }
}

Kết quả của chương trình là:

Hashtable ban đầu: {A=5, C=15, B=10}
Sau khi cập nhật tuổi của A: {A=5, C=15, B=10}
Sau khi xóa B: {A=5, C=15}
Sau khi thay thế tuổi của C: {A=5, C=10}
Sau khi thay thế tuổi của C: {A=5, C=14}
Sau khi sử dụng putIfAbsent cho D: {A=5, D=20, C=14}

Ví dụ về cách sử dụng các phương thức get(), containsValue(), containsKey(), isEmpty() và size()

Dưới đây là một ví dụ về cách sử dụng các phương thức get(), containsValue(), containsKey(), isEmpty() và size() trong lớp Hashtable:

Ví dụ: Example.java

import java.util.Hashtable;

public class Example {
    public static void main(String[] args) {
        // Tạo một đối tượng Hashtable
        Hashtable<String, Integer> hashtable = new Hashtable<>();

        // Thêm cặp khóa-giá trị vào Hashtable
        hashtable.put("A", 30);
        hashtable.put("B", 25);
        hashtable.put("C", 35);

        // Sử dụng phương thức get(Object key) để lấy giá trị theo khóa
        Integer aAge = hashtable.get("A");
        System.out.println("Tuổi của A là: " + aAge);

        // Kiểm tra xem Hashtable có chứa khóa cụ thể không
        boolean containsB = hashtable.containsKey("B");
        System.out.println("Hashtable có chứa khóa 'B': " + containsB);

        // Kiểm tra xem Hashtable có chứa giá trị cụ thể không
        boolean containsAge30 = hashtable.containsValue(30);
        System.out.println("Hashtable có chứa giá trị 30: " + containsAge30);

        // Trả về số lượng cặp khóa-giá trị trong Hashtable
        int size = hashtable.size();
        System.out.println("Số lượng cặp khóa-giá trị trong Hashtable: " + size);

        // Kiểm tra xem Hashtable có rỗng hay không
        boolean isEmpty = hashtable.isEmpty();
        System.out.println("Hashtable có rỗng không: " + isEmpty);
    }
}

Kết quả của chương trình là:

Tuổi của A là: 30
Hashtable có chứa khóa 'B': true
Hashtable có chứa giá trị 30: true
Số lượng cặp khóa-giá trị trong Hashtable: 3
Hashtable có rỗng không: false

Ví dụ về cách sử dụng các phương thức keys(), elements(), keySet() và values()

Dưới đây là một ví dụ về cách sử dụng các phương thức keys(), elements(), keySet() và values() trong lớp Hashtable:

Ví dụ: Example.java

import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Set;

public class Example {
    public static void main(String[] args) {
        // Tạo một Hashtable và thêm một số cặp khóa-giá trị
        Hashtable<String, Integer> hashtable = new Hashtable<>();
        hashtable.put("Alice", 30);
        hashtable.put("Bob", 25);
        hashtable.put("Charlie", 35);

        // Sử dụng keys() để lấy một enumeration của các khóa
        Enumeration<String> keys = hashtable.keys();
        System.out.println("Các khóa trong Hashtable:");
        while (keys.hasMoreElements()) {
            String key = keys.nextElement();
            System.out.println(key);
        }

        // Sử dụng elements() để lấy một enumeration của các giá trị
        Enumeration<Integer> values = hashtable.elements();
        System.out.println("\nCác giá trị trong Hashtable:");
        while (values.hasMoreElements()) {
            Integer value = values.nextElement();
            System.out.println(value);
        }

        // Sử dụng keySet() để lấy một tập hợp các khóa
        Set<String> keySet = hashtable.keySet();
        System.out.println("\nTập hợp các khóa trong Hashtable:");
        for (String key : keySet) {
            System.out.println(key);
        }

        // Sử dụng values() để lấy một tập hợp các giá trị
        Collection<Integer> valueCollection = hashtable.values();
        System.out.println("\nTập hợp các giá trị trong Hashtable:");
        for (Integer value : valueCollection) {
            System.out.println(value);
        }
    }
}

Kết quả của chương trình là:

Các khóa trong Hashtable:
Bob
Charlie
Alice

Các giá trị trong Hashtable:
25
35
30

Tập hợp các khóa trong Hashtable:
Bob
Charlie
Alice

Tập hợp các giá trị trong Hashtable:
25
35
30

Ví dụ về cách sử dụng các phương thức entrySet()

Dưới đây là một ví dụ về cách sử dụng phương thức entrySet() trong lớp Hashtable:

Ví dụ: Example.java

import java.util.Hashtable;
import java.util.Map;
import java.util.Set;

public class Example {
    public static void main(String[] args) {
        // Tạo một Hashtable và thêm một số cặp khóa-giá trị
        Hashtable<String, Integer> hashtable = new Hashtable<>();
        hashtable.put("Alice", 30);
        hashtable.put("Bob", 25);
        hashtable.put("Charlie", 35);

        // Sử dụng entrySet() để lấy một tập hợp các cặp khóa-giá trị (Map.Entry)
        Set<Map.Entry<String, Integer>> entrySet = hashtable.entrySet();

        // Duyệt qua các cặp khóa-giá trị và in ra
        System.out.println("Các cặp khóa-giá trị trong Hashtable:");
        for (Map.Entry<String, Integer> entry : entrySet) {
            System.out.println("Khóa: " + entry.getKey() + ", Giá trị: " + entry.getValue());
        }
    }
}

Kết quả của chương trình là:

Các cặp khóa-giá trị trong Hashtable:
Khóa: Bob, Giá trị: 25
Khóa: Charlie, Giá trị: 35
Khóa: Alice, Giá trị: 30

Ví dụ về cách sử dụng các phương thức hashCode() và equals(Object o)

Dưới đây là một ví dụ minh họa về cách sử dụng hai phương thức hashCode() và equals(Object o) trong lớp Hashtable:

Ví dụ: Example.java

import java.util.Hashtable;

public class Example {
    public static void main(String[] args) {
        // Tạo hai đối tượng Hashtable với cùng các cặp khóa-giá trị
        Hashtable<String, Integer> hashtable1 = new Hashtable<>();
        hashtable1.put("A", 30);
        hashtable1.put("B", 25);
        hashtable1.put("C", 35);

        Hashtable<String, Integer> hashtable2 = new Hashtable<>();
        hashtable2.put("A", 30);
        hashtable2.put("B", 25);
        hashtable2.put("C", 35);

        // Sử dụng phương thức hashCode() để lấy mã băm của các Hashtable
        int hashCode1 = hashtable1.hashCode();
        int hashCode2 = hashtable2.hashCode();

        // In mã băm của các Hashtable
        System.out.println("Mã băm của hashtable1: " + hashCode1);
        System.out.println("Mã băm của hashtable2: " + hashCode2);

        // Sử dụng phương thức equals() để so sánh hai Hashtable
        boolean areEqual = hashtable1.equals(hashtable2);

        // In kết quả so sánh
        if (areEqual) {
            System.out.println("hashtable1 và hashtable2 bằng nhau.");
        } else {
            System.out.println("hashtable1 và hashtable2 không bằng nhau.");
        }
    }
}

Kết quả của chương trình là:

Mã băm của hashtable1: 282
Mã băm của hashtable2: 282
hashtable1 và hashtable2 bằng nhau.

Ví dụ sử dụng Iterator để duyệt các phần tử của Hashtable

Để duyệt các phần tử trong một Hashtable sử dụng Iterator, bạn có thể sử dụng các Iterator để duyệt qua các khóa, giá trị, hoặc các cặp khóa-giá trị (entry) của Hashtable. Dưới đây là một ví dụ minh họa cách thực hiện điều này:

Ví dụ: Example.java

import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;

public class Example {
    public static void main(String[] args) {
        // Tạo một Hashtable với khóa là String và giá trị là Integer
        Hashtable<String, Integer> hashtable = new Hashtable<>();

        // Thêm các cặp khóa-giá trị vào Hashtable
        hashtable.put("One", 1);
        hashtable.put("Two", 2);
        hashtable.put("Three", 3);
        hashtable.put("Four", 4);

        // Duyệt qua các khóa của Hashtable sử dụng Iterator
        System.out.println("Duyệt qua các khóa:");
        Iterator<String> keyIterator = hashtable.keySet().iterator();
        while (keyIterator.hasNext()) {
            String key = keyIterator.next();
            System.out.println("Khóa: " + key);
        }

        // Duyệt qua các giá trị của Hashtable sử dụng Iterator
        System.out.println("\nDuyệt qua các giá trị:");
        Iterator<Integer> valueIterator = hashtable.values().iterator();
        while (valueIterator.hasNext()) {
            Integer value = valueIterator.next();
            System.out.println("Giá trị: " + value);
        }

        // Duyệt qua các cặp khóa-giá trị của Hashtable sử dụng Iterator
        System.out.println("\nDuyệt qua các cặp khóa-giá trị:");
        Iterator<Map.Entry<String, Integer>> entryIterator = hashtable.entrySet().iterator();
        while (entryIterator.hasNext()) {
            Map.Entry<String, Integer> entry = entryIterator.next();
            System.out.println("Khóa: " + entry.getKey() + ", Giá trị: " + entry.getValue());
        }
    }
}

Kết quả của chương trình là:

Duyệt qua các khóa:
Khóa: One
Khóa: Three
Khóa: Four
Khóa: Two

Duyệt qua các giá trị:
Giá trị: 1
Giá trị: 3
Giá trị: 4
Giá trị: 2

Duyệt qua các cặp khóa-giá trị:
Khóa: One, Giá trị: 1
Khóa: Three, Giá trị: 3
Khóa: Four, Giá trị: 4
Khóa: Two, Giá trị: 2

Ví dụ về cách sử dụng Hashtable trong Java với các lớp do người dùng tự định nghĩa

Dưới đây là một ví dụ về cách sử dụng Hashtable trong Java với các lớp do người dùng tự định nghĩa. Ví dụ này sẽ bao gồm việc tạo một lớp Student đại diện cho thông tin của một sinh viên, sau đó sử dụng Hashtable để lưu trữ các đối tượng Student với mã sinh viên làm khóa.

Ví dụ: Example.java

import java.util.Hashtable;
import java.util.Objects;
class Student {
    private String id;
    private String name;
    private int age;

    public Student(String id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Student{" +
               "id='" + id + '\'' +
               ", name='" + name + '\'' +
               ", age=" + age +
               '}';
    }

    // Phương thức equals và hashCode được ghi đè để so sánh và lưu trữ các đối tượng trong Hashtable.
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return id.equals(student.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}
public class Example {
    public static void main(String[] args) {
        // Tạo một Hashtable với khóa là String (mã sinh viên) và giá trị là đối tượng Student
        Hashtable<String, Student> students = new Hashtable<>();

        // Thêm các đối tượng Student vào Hashtable
        students.put("S01", new Student("S01", "A", 20));
        students.put("S02", new Student("S02", "B", 22));
        students.put("S03", new Student("S03", "C", 19));

        // Truy xuất thông tin của một sinh viên dựa trên mã sinh viên
        Student student = students.get("S02");
        System.out.println("Thông tin sinh viên có mã S02: " + student);

        // Kiểm tra xem Hashtable có chứa một mã sinh viên nhất định không
        boolean hasStudent = students.containsKey("S04");
        System.out.println("Có sinh viên nào có mã S04 không? " + (hasStudent ? "Có" : "Không"));

        // Duyệt qua tất cả các sinh viên trong Hashtable
        for (String key : students.keySet()) {
            System.out.println("Mã sinh viên: " + key + ", Thông tin: " + students.get(key));
        }

        // Xóa một sinh viên khỏi Hashtable
        students.remove("S01");
        System.out.println("Danh sách sinh viên sau khi xóa mã S01:");
        for (String key : students.keySet()) {
            System.out.println("Mã sinh viên: " + key + ", Thông tin: " + students.get(key));
        }
    }
}

Kết quả của chương trình là:

Thông tin sinh viên có mã S02: Student{id='S02', name='B', age=22}
Có sinh viên nào có mã S04 không? Không
Mã sinh viên: S01, Thông tin: Student{id='S01', name='A', age=20}
Mã sinh viên: S03, Thông tin: Student{id='S03', name='C', age=19}
Mã sinh viên: S02, Thông tin: Student{id='S02', name='B', age=22}
Danh sách sinh viên sau khi xóa mã S01:
Mã sinh viên: S03, Thông tin: Student{id='S03', name='C', age=19}
Mã sinh viên: S02, Thông tin: Student{id='S02', name='B', age=22}

Như vậy, chúng ta đã tìm hiểu các phương thức chính của lớp Hashtable. Đây là một trong những lớp Map đầu tiên của Java, nổi bật với tính chất đồng bộ (synchronized), đảm bảo an toàn cho môi trường đa luồng. Mặc dù ngày nay các lớp như ConcurrentHashMap thường được ưu tiên vì hiệu suất tốt hơn, Hashtable vẫn là một phần quan trọng trong lịch sử của Java Collections Framework và cần được hiểu rõ, đặc biệt khi làm việc với các hệ thống cũ.

Câu Nói Truyền Cảm Hứng

“Bắt đầu ở đâu không quan trọng, quan trọng là bạn sẵn sàng bắt đầu.” – W. Clement Stone

Không Gian Tích Cực

“Chúc bạn luôn giữ vững niềm tin và sức mạnh để vượt qua mọi thử thách trong cuộc sống.”