Java中的Map是一种非常常见的数据结构,其具有键值对的形式存储,通常用来存储一组相关的数据。而put方法是Map接口中的一种方法,该方法用来将一组键值对存储到Map中。在本篇文章中,我们将从多个方面介绍Java中put方法的使用。
一、put方法的基本使用
首先,我们来看一下put方法的基本使用:
Map<String, String> map = new HashMap<>();
map.put("name", "Tom");
map.put("age", "18");
上述代码中,我们首先定义了一个Map实例,然后使用put方法将两组键值对存储到Map中。在这里,我们传入的是一个String类型的键和一个String类型的值。需要注意的是,在使用put方法的时候,如果Map中已经存在了这个键,则会用新的值替换旧的值。
二、put方法的返回值
除了将一组键值对存储到Map中之外,put方法还可以返回该键对应的旧值。例如:
Map<String, String> map = new HashMap<>();
map.put("name", "Tom");
String oldValue = map.put("name", "Jerry");
System.out.println(oldValue); // 输出Tom
上述代码中,我们首先使用put方法将键为”name”、值为”Tom”的键值对存储到Map中。接着,我们再次使用put方法,将键为”name”、值为”Jerry”的键值对存储到Map中。注意到在此过程中,Map中名为”name”的键已经存在,因此使用新的值”Jerry”替换掉了旧值”Tom”。而此时,put方法返回的值就是被替换掉的旧值”Tom”。
三、put方法的默认实现
Map接口中提供了多个不同的实现类,如HashMap、TreeMap、ConcurrentHashMap等。而在这些实现类中,put方法的具体实现也是不同的。下面我们来详细介绍一下HashMap和TreeMap中put方法的默认实现。
1. HashMap中put方法的默认实现
HashMap是一种散列表,它采用了”拉链法”来解决哈希冲突。下面是HashMap中put方法的默认实现:
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
// 省略其他代码段
}
modCount++; // 记录Map中实际存储的键值对数量
if (++size >= threshold) // 如果Map中的键值对数量超过了扩容阈值
resize(); // 则进行扩容
afterNodeInsertion(evict);
return null;
}
上述代码中,我们可以看到put方法的具体实现其实是调用了putVal方法,这个方法就是HashMap中put方法的具体实现。在这个方法中,我们可以看到,首先通过hash方法计算出了当前键对应的哈希值。接着,如果键对应的槽位没有被占用,就直接在该槽位中存储该键值对。否则,就需要对已经存在的键值对进行更新操作。最后,如果Map中的键值对数量超过了扩容阈值,就需要进行扩容操作。
2. TreeMap中put方法的默认实现
TreeMap是一种基于红黑树的映射。下面是TreeMap中put方法的默认实现:
public V put(K key, V value) {
Entry<K,V> t = root;
if (t == null) {
compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp; Entry<K,V> parent;
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
if (key == null)
throw new NullPointerException();
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
上述代码中,我们可以看到put方法的具体实现是直接在TreeMap中新建一个Entry实例,并将其插入到红黑树中。在实现中,首先通过比较器(如果存在)或者键实现Comparable接口的compareTo方法(如果键没有指定比较器并且实现了Comparable接口)来判断当前键应该插入到红黑树的哪个位置。接着,如果节点已经存在,则用新的值替换旧的值,否则就将新节点插入到红黑树中。最后,如果摆动操作遵循红黑树插入的规则。
四、put方法的使用技巧
做到了上述的put方法的基本使用、返回值、默认实现,接下来我们将介绍一些使用技巧。
1. 使用putIfAbsent方法避免键的重复插入
在实际开发中,有时候需要向Map中插入一组键值对,但是如果键已经存在,则不插入。这个需求可以通过putIfAbsent方法来实现。例如:
Map<String, String> map = new HashMap<>();
map.put("name", "Tom");
map.putIfAbsent("name", "Jerry");
System.out.println(map.get("name")); // 输出Tom
上述代码中,由于”Tom”已经被存储为”name”键的值,因此使用putIfAbsent方法插入”Jerry”时会失败,不会对Map做出任何修改。在输出时,我们可以发现”name”键的值仍然为”Tom”。
2. 使用putAll方法批量插入键值对
如果需要将一个Map中的所有键值对都插入到另一个Map中,那么可以使用putAll方法。例如:
Map<String, String> map1 = new HashMap<>();
map1.put("name", "Tom");
map1.put("age", "18");
Map<String, String> map2 = new HashMap<>();
map2.putAll(map1);
System.out.println(map2.get("name")); // 输出Tom
System.out.println(map2.get("age")); // 输出18
上述代码中,我们首先定义了map1,并向其中插入了两组键值对。接着,我们定义了一个空的map2,使用putAll方法将map1中的所有键值对都插入到map2中。最后,我们通过get方法检验了一下map2中存储的键值对是否正确。
3. 使用computeIfAbsent方法避免重复计算
在实际开发中,有时候需要根据键的值来计算一些数据,并将计算结果存储到Map中。如果键的值已经对应了一个存储的计算结果,那么就可以直接获取这个结果而不需要重复计算。这个需求可以使用computeIfAbsent方法来实现。例如:
Map<String, Integer> map = new HashMap<>();
map.put("count", 1);
Integer result = map.computeIfAbsent("count", key -> computeCount(key));
System.out.println(result); // 输出1
上述代码中,我们首先定义了一个名为count的键,对应的值为1。接着,我们使用computeIfAbsent方法来获取该键对应的计算结果。在这里,computeIfAbsent方法会首先检查名为count的键是否存在。由于count键已经被存储在map中,因此computeIfAbsent方法不会对该键进行计算,而是直接返回其对应的值1。最后,我们通过输出检查一下返回值是否为1。
五、小结
本文主要介绍了Java中Map接口中的put方法。我们从put方法的基本使用、返回值、默认实现和使用技巧四个方面进行了详细的介绍。除此之外,还结合具体的代码实现,帮助读者更加深入地了解Java中put方法的使用。
原创文章,作者:SJSQ,如若转载,请注明出处:https://www.506064.com/n/140078.html
微信扫一扫
支付宝扫一扫