Rate this post

HashMap<K, V> là một phần trong collection của Java kể từ Java 1.2. Lớp này được tìm thấy trong gói java.util. Nó cung cấp triển khai cơ bản của interface Map của Java. Nó lưu trữ dữ liệu theo cặp (key, value) và bạn có thể truy cập chúng bằng một chỉ mục thuộc loại khác (ví dụ: Số nguyên). Một đối tượng được sử dụng làm key (chỉ mục) cho đối tượng (value) khác. Nếu bạn cố chèn key trùng lặp, nó sẽ thay thế phần tử của key tương ứng.

Các bài viết liên quan:

HashMap tương tự như HashTable, nhưng nó không được đồng bộ hóa. Nó cũng cho phép lưu trữ các key null, nhưng chỉ nên có một đối tượng key null và có thể có bất kỳ số lượng value null nào. Lớp này không đảm bảo về thứ tự của Map. Để sử dụng lớp này và các phương thức của nó, bạn cần nhập gói java.util.HashMap hoặc lớp cha của nó.

// Java program to illustrate HashMap class of java.util
// package

// Importing HashMap class
import java.util.HashMap;

// Main class
public class GFG {

	// Main driver method
	public static void main(String[] args)
	{
		// Create an empty hash map by declaring object
		// of string and integer type
		HashMap<String, Integer> map = new HashMap<>();

		// Adding elements to the Map
		// using standard put() method
		map.put("vishal", 10);
		map.put("sachin", 30);
		map.put("vaibhav", 20);

		// Print size and content of the Map
		System.out.println("Size of map is:- "
						+ map.size());

		// Printing elements in object of Map
		System.out.println(map);

		// Checking if a key is present and if
		// present, print value by passing
		// random element
		if (map.containsKey("vishal")) {

			// Mapping
			Integer a = map.get("vishal");

			// Printing value for the corresponding key
			System.out.println("value for key"
							+ " \"vishal\" is:- " + a);
		}
	}
}

Hệ thống phân cấp của HashMap như sau:

  Cú pháp: Khai báo

public class HashMap<K,V> extends AbstractMap<K,V>
                          implements Map<K,V>, Cloneable, Serializable

Tham số: Nó có hai tham số cụ thể như sau:

  • Loại key được duy trì bởi Map này
  • Loại value được ánh xạ

HashMap triển khai các interface Có thể nối tiếp, Có thể sao chép, Map<K, V>. HashMap mở rộng lớp AbstractMap<K, V>. Các lớp con trực tiếp là LinkedHashMap, PrinterStateReasons.

Constructor trong HashMap như sau:

HashMap cung cấp 4 hàm tạo và công cụ sửa đổi truy cập của mỗi hàm là công khai được liệt kê như sau:

  1. HashMap()
  2. HashMap(int initialCapacity)
  3. HashMap(int initialCapacity, float loadFactor)
  4. HashMap(Map map)

Bây giờ hãy thảo luận từng hàm tạo bên trên cùng với việc triển khai tương tự với sự trợ giúp của các chương trình java sạch.

Constructor 1: HashMap()

Nó là hàm tạo mặc định tạo ra một phiên bản của HashMap với dung lượng ban đầu là 16 và hệ số tải là 0,75.

Cú pháp:

HashMap<K, V> hm = new HashMap<K, V>();

Thí dụ

// Java program to Demonstrate the HashMap() constructor

// Importing basic required classes
import java.io.*;
import java.util.*;

// Main class
// To add elements to HashMap
class GFG {

	// Main driver method
	public static void main(String args[])
	{
		// No need to mention the
		// Generic type twice
		HashMap<Integer, String> hm1 = new HashMap<>();

		// Initialization of a HashMap using Generics
		HashMap<Integer, String> hm2
			= new HashMap<Integer, String>();

		// Adding elements using put method
		// Custom input elements
		hm1.put(1, "one");
		hm1.put(2, "two");
		hm1.put(3, "three");

		hm2.put(4, "four");
		hm2.put(5, "five");
		hm2.put(6, "six");

		// Print and display mapping of HashMap 1
		System.out.println("Mappings of HashMap hm1 are : "
						+ hm1);

		// Print and display mapping of HashMap 2
		System.out.println("Mapping of HashMap hm2 are : "
						+ hm2);
	}
}

Constructor 2: HashMap(int initialCapacity)

Nó tạo một phiên bản HashMap vớiinitialCapacity được chỉ định và loadFactor là 0,75.

Cú pháp:

HashMap<K, V> hm = new HashMap<K, V>(int initialCapacity);

Thí dụ

// Java program to Demonstrate
// HashMap(int initialCapacity) Constructor

// Importing basic classes
import java.io.*;
import java.util.*;

// Main class
// To add elements to HashMap
class AddElementsToHashMap {

	// Main driver method
	public static void main(String args[])
	{
		// No need to mention the
		// Generic type twice
		HashMap<Integer, String> hm1 = new HashMap<>(10);

		// Initialization of a HashMap using Generics
		HashMap<Integer, String> hm2
			= new HashMap<Integer, String>(2);

		// Adding elements to object of HashMap
		// using put method

		// HashMap 1
		hm1.put(1, "one");
		hm1.put(2, "two");
		hm1.put(3, "three");

		// HashMap 2
		hm2.put(4, "four");
		hm2.put(5, "five");
		hm2.put(6, "six");

		// Printing elements of HashMap 1
		System.out.println("Mappings of HashMap hm1 are : "
						+ hm1);

		// Printing elements of HashMap 2
		System.out.println("Mapping of HashMap hm2 are : "
						+ hm2);
	}
}

Constructor 3: HashMap(int initialCapacity, float loadFactor)

Nó tạo ra một phiên bản HashMap vớiinitialCapacity được chỉ định vàloadFactor được chỉ định.

Cú pháp:

HashMap<K, V> hm = new HashMap<K, V>(int initialCapacity, int  loadFactor);

Thí dụ

// Java program to Demonstrate
// HashMap(int initialCapacity,float loadFactor) Constructor

// Importing basic classes
import java.io.*;
import java.util.*;

// Main class
// To add elements to HashMap
class GFG {

	// Main driver method
	public static void main(String args[])
	{
		// No need to mention the generic type twice
		HashMap<Integer, String> hm1
			= new HashMap<>(5, 0.75f);

		// Initialization of a HashMap using Generics
		HashMap<Integer, String> hm2
			= new HashMap<Integer, String>(3, 0.5f);

		// Add Elements using put() method
		// Custom input elements
		hm1.put(1, "one");
		hm1.put(2, "two");
		hm1.put(3, "three");

		hm2.put(4, "four");
		hm2.put(5, "five");
		hm2.put(6, "six");

		// Print and display elements in object of hashMap 1
		System.out.println("Mappings of HashMap hm1 are : "
						+ hm1);

		// Print and display elements in object of hashMap 2
		System.out.println("Mapping of HashMap hm2 are : "
						+ hm2);
	}
}

HashMap(Map map)

Nó tạo ra một thể hiện của HashMap với các ánh xạ giống như Map đã chỉ định.

HashMap<K, V> hm = new HashMap<K, V>(Map map);
// Java program to demonstrate the
// HashMap(Map map) Constructor

import java.io.*;
import java.util.*;

class AddElementsToHashMap {
	public static void main(String args[])
	{
		// No need to mention the
		// Generic type twice
		Map<Integer, String> hm1 = new HashMap<>();

		// Add Elements using put method
		hm1.put(1, "one");
		hm1.put(2, "two");
		hm1.put(3, "three");

		// Initialization of a HashMap
		// using Generics
		HashMap<Integer, String> hm2
			= new HashMap<Integer, String>(hm1);

		System.out.println("Mappings of HashMap hm1 are : "
						+ hm1);
	
		System.out.println("Mapping of HashMap hm2 are : "
						+ hm2);
	}
}

Toán tử khác nhau trên HashMap

Thêm phần tử:

Để thêm phần tử vào Map, chúng ta có thể sử dụng phương thức put(). Tuy nhiên, thứ tự chèn không được giữ lại trong Hashmap. Trong nội bộ, đối với mọi phần tử, một hàm băm riêng được tạo và các phần tử được lập chỉ mục dựa trên hàm băm này để làm cho nó hiệu quả hơn.

// Java program to add elements
// to the HashMap

import java.io.*;
import java.util.*;

class AddElementsToHashMap {
	public static void main(String args[])
	{
		// No need to mention the
		// Generic type twice
		HashMap<Integer, String> hm1 = new HashMap<>();

		// Initialization of a HashMap
		// using Generics
		HashMap<Integer, String> hm2
			= new HashMap<Integer, String>();

		// Add Elements using put method
		hm1.put(1, "AddElementsToHashMap1");
		hm1.put(2, "For");
		hm1.put(3, "AddElementsToHashMap2");

		hm2.put(1, "AddElementsToHashMap3");
		hm2.put(2, "For");
		hm2.put(3, "AddElementsToHashMap4");

		System.out.println("Mappings of HashMap hm1 are : "
						+ hm1);
		System.out.println("Mapping of HashMap hm2 are : "
						+ hm2);
	}
}

Thay đổi phần tử:

Sau khi thêm phần tử, nếu chúng ta muốn thay đổi phần tử, có thể thực hiện bằng cách thêm lại phần tử đó bằng phương thức put(). Vì các thành phần trong Map được lập chỉ mục bằng cách sử dụng các key, value của key có thể được thay đổi bằng cách chỉ cần chèn value cập nhật cho key cho mà chúng tôi muốn thay đổi.

// Java program to change
// elements of HashMap

import java.io.*;
import java.util.*;
class ChangeElementsOfHashMap {
	public static void main(String args[])
	{

		// Initialization of a HashMap
		HashMap<Integer, String> hm
			= new HashMap<Integer, String>();

		// Change Value using put method
		hm.put(1, "ChangeElementsOfHashMap1");
		hm.put(2, "ChangeElementsOfHashMap2");
		hm.put(3, "ChangeElementsOfHashMap3");

		System.out.println("Initial Map " + hm);

		hm.put(2, "For");

		System.out.println("Updated Map " + hm);
	}
}

Xóa phần tử:

Để xóa phần tử khỏi Map, chúng ta có thể sử dụng phương thức remove(). Phương thức này lấy value key và xóa ánh xạ cho key khỏi Map này nếu nó có trong Map.

// Java program to remove
// elements from HashMap

import java.io.*;
import java.util.*;
class RemoveElementsOfHashMap{
	public static void main(String args[])
	{
		// Initialization of a HashMap
		Map<Integer, String> hm
			= new HashMap<Integer, String>();

		// Add elements using put method
		hm.put(1, "RemoveElementsOfHashMap1");
		hm.put(2, "For");
		hm.put(3, "RemoveElementsOfHashMap2");
		hm.put(4, "For");

		// Initial HashMap
		System.out.println("Mappings of HashMap are : "
						+ hm);

		// remove element with a key
		// using remove method
		hm.remove(4);

		// Final HashMap
		System.out.println("Mappings after removal are : "
						+ hm);
	}
}

Tra cứu HashMap

Chúng ta có thể sử dụng interface Iterator để duyệt qua bất kỳ cấu trúc nào của Khung collection. Vì Iterators hoạt động với một loại dữ liệu nên chúng tôi sử dụng Entry< ? , ? > để giải quyết hai loại riêng biệt thành một định dạng tương thích. Sau đó, sử dụng phương thức next(), chúng tôi in các mục của HashMap.

// Java program to traversal a
// Java.util.HashMap

import java.util.HashMap;
import java.util.Map;

public class TraversalTheHashMap {
	public static void main(String[] args)
	{
		// initialize a HashMap
		HashMap<String, Integer> map = new HashMap<>();

		// Add elements using put method
		map.put("vishal", 10);
		map.put("sachin", 30);
		map.put("vaibhav", 20);

		// Iterate the map using
		// for-each loop
		for (Map.Entry<String, Integer> e : map.entrySet())
			System.out.println("Key: " + e.getKey()
							+ " Value: " + e.getValue());
	}
}

Các tính năng quan trọng của HashMap

Để truy cập một value, người ta phải biết key của nó. HashMap được gọi là HashMap vì nó sử dụng một kỹ thuật gọi là Băm. Băm là một kỹ thuật chuyển đổi một Chuỗi lớn thành Chuỗi nhỏ đại diện cho cùng một Chuỗi. value ngắn hơn giúp lập chỉ mục và tìm kiếm nhanh hơn. HashSet cũng sử dụng HashMap trong nội bộ.

Vài tính năng quan trọng của HashMap là:

  • HashMap là một phần của gói java.util.
  • HashMap mở rộng một lớp trừu tượng AbstractMap, lớp này cũng cung cấp triển khai interface Map không đầy đủ.
  • Nó cũng thực hiện interface Cloneable và Serializable. K và V trong định nghĩa trên tương ứng đại diện cho key và value.
  • HashMap không cho phép các key trùng lặp nhưng cho phép các value trùng lặp. Điều đó có nghĩa là Một key duy nhất không thể chứa nhiều hơn 1 value nhưng nhiều hơn 1 key có thể chứa một value.
  • HashMap cũng cho phép key null nhưng chỉ một lần và nhiều value null.
  • Class này không đảm bảo về thứ tự của Map; đặc biệt, nó không đảm bảo rằng thứ tự sẽ không đổi theo thời gian. Nó gần giống với HashTable nhưng không được đồng bộ hóa.

Cấu trúc bên trong của HashMap

Nội bộ HashMap chứa một mảng Nút và một nút được biểu diễn dưới dạng một lớp chứa 4 trường:

  1. int hash
  2. K key
  3. V value
  4. Node next

Có thể thấy rằng node đang chứa một tham chiếu đến đối tượng của chính nó. Vì vậy, nó là một danh sách được liên kết.


Hiệu suất của HashMap

Hiệu suất của HashMap phụ thuộc vào 2 tham số được đặt tên như sau:

  1. Initial Capacity
  2. Load Factor

1. Initial Capacity – Đó là dung lượng của HashMap tại thời điểm tạo (Đó là số bộ chứa mà HashMap có thể chứa khi HashMap được khởi tạo). Trong java, ban đầu nó là 2^4=16, nghĩa là nó có thể chứa 16 cặp key-value.

2. Load Factor – Đó là value phần trăm của dung lượng mà sau đó dung lượng của Hashmap sẽ được tăng lên (Đó là phần trăm lấp đầy các bộ chứa sau đó Quá trình băm lại diễn ra). Trong java, nó là 0,75f theo mặc định, nghĩa là quá trình băm lại diễn ra sau khi lấp đầy 75% dung lượng.

3. Threshold – Nó là sản phẩm của Load FactorInitial Capacity. Trong java, theo mặc định, nó là (16 * 0.75 = 12). Nghĩa là, Quá trình băm lại diễn ra sau khi chèn 12 cặp key-value vào HashMap.

4. Rehashing – Đây là quá trình nhân đôi dung lượng của HashMap sau khi đạt đến Threshold. Trong java, HashMap tiếp tục chạy lại (theo mặc định) theo trình tự sau – 2^4, 2^5, 2^6, 2^7, …. Sớm.

Nếu . Initial Capacity được giữ cao hơn thì việc băm lại sẽ không bao giờ được thực hiện. Nhưng bằng cách giữ nó cao hơn sẽ làm tăng độ phức tạp về thời gian của phép lặp. Vì vậy, nó nên được lựa chọn rất khéo léo để tăng hiệu suất. Số lượng value dự kiến nên được tính đến để đặt dung lượng ban đầu. value hệ số tải được ưu tiên chung nhất là 0,75 mang lại sự thỏa thuận tốt giữa chi phí thời gian và không gian. value của hệ số tải thay đổi trong keyng từ 0 đến 1.

Lưu ý: Từ Java 8 trở đi, Java đã bắt đầu sử dụng BST Tự cân bằng thay vì danh sách được liên kết để xâu chuỗi. Ưu điểm của bst tự cân bằng là, chúng ta gặp trường hợp xấu nhất (khi mọi phím ánh xạ tới cùng một vị trí) thời gian tìm kiếm là O(Log n).

HashMap được đồng bộ hóa

Như đã nói rằng HashMap không được đồng bộ hóa, tức là nhiều luồng có thể truy cập nó đồng thời. Nếu nhiều luồng truy cập lớp này đồng thời và ít nhất một luồng điều khiển nó theo cấu trúc thì cần phải làm cho nó được đồng bộ hóa bên ngoài. Nó được thực hiện bằng cách đồng bộ hóa một số đối tượng đóng gói Map. Nếu Không có đối tượng như vậy tồn tại thì nó có thể được bọc xung quanh Collections.synchronizedMap() để làm cho HashMap được đồng bộ hóa và tránh truy cập không đồng bộ ngẫu nhiên. Như trong ví dụ sau:

Map m = Collections.synchronizedMap(new HashMap(...));

Bây giờ Map m đã được đồng bộ hóa. Các trình lặp của lớp này sẽ không thành công nếu bất kỳ sửa đổi cấu trúc nào được thực hiện sau khi tạo trình lặp, theo bất kỳ cách nào ngoại trừ thông qua phương thức loại bỏ của trình lặp. Trong trường hợp iterator gặp lỗi, nó sẽ ném ra ConcurrentModificationException.

Độ phức tạp về thời gian của HashMap: HashMap cung cấp độ phức tạp về thời gian không đổi cho các hoạt động cơ bản, nhận và đặt nếu hàm băm được viết đúng cách và nó phân tán đúng các phần tử giữa các nhóm. Việc lặp lại HashMap phụ thuộc vào dung lượng của HashMap và một số cặp key-value. Về cơ bản, nó tỷ lệ thuận với dung lượng + kích thước. Dung lượng là số lượng thùng trong HashMap. Vì vậy, ban đầu không nên giữ một số lượng lớn các thùng trong HashMap.

Các ứng dụng của HashMap: HashMap chủ yếu là việc thực hiện băm. Nó rất hữu ích khi chúng ta cần triển khai hiệu quả các hoạt động tìm kiếm, chèn và xóa. Vui lòng tham khảo các ứng dụng băm để biết chi tiết.

Các phương thức trong HashMap

  • K – Loại key trong Map.
  • V – Loại value được ánh xạ trong Map.
  • clear() Xóa tất cả ánh xạ khỏi Map này.
  • clone() Trả về một bản sao nông của phiên bản HashMap này: bản thân các key và value không được sao chép.
  • compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) Cố gắng tính toán ánh xạ cho key đã chỉ định và value đượ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 key được chỉ định chưa được liên kết với một value (hoặc được ánh xạ thành null), hãy thử tính value của nó bằng cách sử dụng hàm ánh xạ đã cho và nhập value đó vào Map này trừ khi null.
  • computeIfPresent(K key, BiFunction<? super K, ? super V, ?extend V> remappingFunction) Nếu có value cho key đã chỉ định và không phải là null, thì hãy thử tính toán một ánh xạ mới cho key và value được ánh xạ hiện tại của nó.
  • containsKey(key đối tượng) Trả về true nếu Map này chứa ánh xạ cho key đã chỉ định.
  • containsValue(value đối tượng) Trả về true nếu Map này ánh xạ một hoặc nhiều key tới value đã chỉ định.
  • entrySet() Trả về viewTập hợp của các ánh xạ có trong Map này.
  • get(key đối tượng) Trả về value mà key đã chỉ định được ánh xạ tới hoặc null nếu ánh xạ này không chứa ánh xạ cho key.
  • isEmpty() Trả về true nếu Map này không chứa ánh xạ key-value.
  • keySet() Trả về chế độ xem Tập hợp của các key có trong Map này.
  • merge(K key, V value, BiFunction<? super V, ? super V, ?extend V> remappingFunction) Nếu key được chỉ định chưa được liên kết với một value hoặc được liên kết với null, hãy liên kết nó với value khác null đã cho .
  • put(K key, V value) Liên kết value đã chỉ định với key đã chỉ định trong Map này.
  • putAll(Map<? extends K,?extend V> m) Sao chép tất cả các ánh xạ từ Map đã chỉ định sang Map này.
  • remove(key đối tượng) Xóa ánh xạ cho key đã chỉ định khỏi ánh xạ này nếu có.
  • size() Trả về số ánh xạ key-value trong Map này.
  • values() Trả về chế độ xem collection của các value có trong Map này.

Các phương thức kế thừa từ lớp java.util.AbstractMap

  • equals() So sánh đối tượng được chỉ định với Map này cho bằng nhau.
  • hashCode() Trả về value mã băm cho Map này.
  • toString() Trả về một biểu diễn chuỗi của Map này.

Các phương thức kế thừa từ interface java.util.Map

  • equals() So sánh đối tượng được chỉ định với Map này cho bằng nhau.
  • forEach(BiConsumer<? super K,? super V> action): Thực hiện hành động nhất định cho mỗi entry nhập trong Map này cho đến khi tất cả các mục nhập đã được xử lý hoặc hành động đưa ra một ngoại lệ.
  • getOrDefault(key đối tượng, V defaultValue) Trả về value mà key đã chỉ định được ánh xạ tới hoặc defaultValue nếu ánh xạ này không chứa ánh xạ cho key.
  • hashCode() Trả về value mã băm cho Map này.
  • putIfAbsent(K key, V value) Nếu key được chỉ định chưa được liên kết với một value (hoặc được ánh xạ tới null) thì liên kết nó với value đã cho và trả về null, ngược lại trả về value hiện tại.
  • remove(key đối tượng, value đối tượng) Chỉ xóa mục nhập cho key đã chỉ định nếu nó hiện được ánh xạ tới value đã chỉ định.
  • replace(K key, V value) Chỉ thay thế mục nhập cho key đã chỉ định nếu nó hiện được ánh xạ tới một số value.
  • replace(K key, V oldValue, V newValue) Chỉ thay thế mục nhập cho key đã chỉ định nếu hiện được ánh xạ tới value đã chỉ định.
  • replaceAll(BiFunction<? super K,? super V,? extends V> function): Thay thế value của từng entry 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 đưa ra một ngoại lệ.

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Contact Me on Zalo
Call now