Java集合——HashMap

Java.util.HashMap,继承了AbstractMap,实现了Map、Clonable、Serializable接口。

它是以key-value键值对的形式存放的哈希表,其中key和value都允许null值。


两个重要参数

· 初始容量,默认为16,是哈希表中桶的数量,简单理解为其能存放的key-value键值对个数。

· 加载因子,默认为0.75,是表中已填充的记录数与总容量的比值,当数目达到这一比值时,将会自动扩容为两倍。

加载因子过高会提高空间利用率,但是降低了查找的性能;加载因子过低时可能会有频繁的扩容操作,同样影响性能甚至浪费存储空间。

所以在设置初始容量时应合理预估可能的数据条数以及总容量和加载因子的关系,尽量选用折中的数值。


构造函数

HashMap()  使用默认的初始容量16和加载因子0.75构造一个空的hashmap。

HashMap(int initialCapacity)  使用指定的初始容量initialCapacity和默认的加载因子0.75构造一个空的hashmap。

HashMap(int initialCapacity, float loadFactor)  使用指定的初始容量initialCapacity和指定的加载因子loadFactor构造一个空的hashmap。

HashMap(Map<? extends K, ? extends V> m)  构造与指定Map m相同映射的新HashMap。 HashMap使用默认加载因子0.75,初始容量由指定映射决定,足以将映射保存在指定的映射中。


常用方法

· 插入

V put(K key, V value)  把指定的key和value插入map中。如果map中已存在该key,则原value值将被替换成指定值。返回与该key匹配的原value值。由于hashmap支持value为null值,所以put函数可能返回null,并且有两种情况:在put执行之前,map中不存在指定的key值,或该key的原value值为null。

void putAll(Map<? extends K, ? extends V> m)   把指定的map中的映射都插入到当前map中。如果指定map中有key值已经存在于当前map,则进行value值替换。无返回值。

· 删除

V remove(Object key)  删除与给定key相关联的映射,返回其value值。同样存在两种返回null的情况:map中不存在指定的key值,或该key的原value值为null。

· 修改

boolean replace(K key, V oldValue, V newValue)  把指定的key-oldValue映射中oldValue值替换成newValue。这个操作用put(key, newValue)同样可以实现。

V replace(K key, V value)  只有当给定的key对应的value值不为null时,才将其替换成value。

· 查询

V get(Object key)  返回与给定key值相匹配的value值,不存在该key时返回null

boolean containsKey(Object key)  如果map中包含key值为给定值的映射,则返回true,否则返回false。

boolean containsValue(Object value)  如果map中包含value值为给定值的映射,则返回true,否则返回false。

在上述两种方法中,如果containsKey方法返回为true,则说明map中有且只有一个映射符合条件,如果containsValue返回true,则说明有至少一个,

因为key值不允许重复,而value值允许。

int size()  返回映射数量

boolean isEmpty()  如果map为空(size==0)则返回true,否则返回false


关于entrySet、keySet、values

final class EntrySet extends AbstractSet<Map.Entry<K,V>>  内部类继承了AbstractSet类,而AbstractSet实现了Set接口。它是包含了Map中映射关系的视图,依赖于map,对map进行键值修改会同步修改其entrySet,无需再次赋值。

Set<Map.Entry<K,V>> entrySet()  返回该视图

Map<String, Object> myHashMap = new HashMap<>();
myHashMap.put("key1", "value1");
myHashMap.put("key2", "value2");
       
Set<Map.Entry<String, Object>> entrySet = myHashMap.entrySet();
System.out.println(entrySet.toString());
     
myHashMap.put("key2", "value22");
System.out.println(entrySet.toString());

输出:
[key1=value1, key2=value2]
[key1=value1, key2=value22]<K>
final class KeySet extends AbstractSet<K>  内部类定义了包含map中所有key值的set集合。(map中key值不允许修改,会产生内存泄漏)

Set<K> keySet()  返回这个集合。

Set<String> keySet = myHashMap.keySet();
System.out.println(keySet.toString());
输出:
[key1, key2]
final class Values extends AbstractCollection<V> 内部类定义了包含map中所有value值的集合。由于key值不允许重复,所以key值集合采用了set,而value值允许重复,故为collection。

Collection<V> values()返回这个collection。

Collection values = myHashMap.values();
System.out.println(values.toString());
        
myHashMap.put("key1", "value111");
System.out.println(values.toString());
输出:
[value1, value22]
[value111, value22]


遍历方法与性能比较

entry和迭代器iterator均可用来遍历,六种方法如下,其中value遍历的两种方法只能访问到value值,无法获得key值:

Map<String, String> myHashMap = new HashMap<>();
for(int i = 0; i < 3500000; i++){
    myHashMap.put("key"+i, "value"+i);
}
       
//entrySet遍历
long startTime = System.currentTimeMillis();
Set<Map.Entry<String, String>> entrySet = myHashMap.entrySet();
for(Map.Entry<String, String> entry : entrySet){
    entry.getKey();
    entry.getValue();
}
System.out.println("entrySet遍历: " + (System.currentTimeMillis() - startTime));
        
//keySet遍历
startTime = System.currentTimeMillis();
Set<String> keySet = myHashMap.keySet();
for(String key: keySet){
    myHashMap.get(key);
}
System.out.println("keySet遍历: " + (System.currentTimeMillis() - startTime));

//entry-iterator遍历
startTime = System.currentTimeMillis();
Iterator<Map.Entry<String, String>> entryIterator = myHashMap.entrySet().iterator();
while(entryIterator.hasNext()){
    Map.Entry<String, String> entry = entryIterator.next();
    entry.getKey();
    entry.getValue();
}
System.out.println("entry-itereator遍历: " + (System.currentTimeMillis() - startTime));

//key-iterator遍历
startTime = System.currentTimeMillis();
Iterator<String> keyIterator = myHashMap.keySet().iterator();
while(keyIterator.hasNext()){
    myHashMap.get(keyIterator.next());
}
System.out.println("key-itereator遍历: " + (System.currentTimeMillis() - startTime));

//value遍历
startTime = System.currentTimeMillis();
Collection<String> value = myHashMap.values();
for(String v : value){
    ;
}
System.out.println("value遍历: " + (System.currentTimeMillis() - startTime));

//value-iterator遍历
startTime = System.currentTimeMillis();
Iterator<String> valueIterator = myHashMap.values().iterator();
while(valueIterator.hasNext()){
    valueIterator.next();
}
System.out.println("value-itereator遍历: " + (System.currentTimeMillis() - startTime));
输出:
entrySet遍历: 89
keySet遍历: 115
entry-itereator遍历: 89
key-itereator遍历: 118
value遍历: 96
value-itereator遍历: 83
整体来看,通过key去遍历的方法是效率最低的。这很容易想到,因为它在拿到key的集合或迭代器之后还要再做一次取值才能拿到value,而对于entry,直接就能拿到k-v键值对,无需再次从map中取值。value-iterator遍历效率最高,这仅适用于需要拿到value值而不关心key值的情况。












Java中的HashMap是一种常用的集合类,用于存储键值对。它继承自AbstractMap类,并且实现了Map接口。与HashTable相比,HashMap具有更好的性能和扩展性。[1] HashMap的底层原理是使用哈希表来实现的,它通过将键映射到存储桶中来存储和获取值。HashMap使用键的hashCode()方法来计算哈希码,然后根据哈希码将键值对存储在相应的存储桶中。在存储和获取值时,HashMap会根据键的哈希码进行快速查找,从而实现了O(1)的平均时间复杂度。 在HashMap中,键和值都允许为null,但是只能有一个为null的键。如果多个键映射到同一个存储桶,HashMap会使用链表或红黑树来解决冲突。当链表长度超过一定阈值时,链表会被转换为红黑树,以提高查找效率。 除了HashMap,还有其他一些相关的类可以用来实现线程安全的HashMap,例如Collections.synchronizedMap()方法可以将HashMap转换为同步的Map。这样可以在多线程环境中安全地使用HashMap。不过,由于性能的原因,这种方式不常用。 总结来说,JavaHashMap是一种常用的集合类,使用哈希表来存储键值对。它具有良好的性能和扩展性,允许键和值为null。在多线程环境中可以使用同步的Map来实现线程安全。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Java集合 —— HashMap原理解析](https://blog.csdn.net/m0_56602092/article/details/130338081)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [【javaHashMap底层实现原理及面试题](https://blog.csdn.net/twotwo22222/article/details/128426417)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值