欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java如何根據(jù)key值修改Hashmap中的value值

 更新時間:2023年03月22日 16:49:05   作者:學(xué)習(xí)路上的行人  
這篇文章主要介紹了Java如何根據(jù)key值修改Hashmap中的value值問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

根據(jù)key值修改Hashmap的value值

如果原來map中沒有key,會創(chuàng)建,如果原來有key,會使用value 覆蓋掉原來的值

map.put(key,value);

這個實現(xiàn)對原值加一(前提是有這個key)

map.put(key,map.get(key)+1);

以下可以獲取key對應(yīng)的value,如果沒有可以返回默認(rèn)的value

map.getOrDefault(key,value);

HashMap的key更改后能否正確獲取value?

在HashMap 中存放的一系列鍵值對,其中鍵為某個我們自定義的類型。放入 HashMap 后,我們在外部把某一個 key 的屬性進(jìn)行更改,然后我們再用這個 key 從 HashMap 里取出元素,這時候 HashMap 會返回什么?

我們辦公室?guī)讉€人答案都不一致,有的說返回null,有的說能正常返回value。但不論答案是什么都沒有確鑿的理由。我覺得這個問題挺有意思的,就寫了代碼測試。結(jié)果是返回null。需要說明的是我們自定義的類重寫了 hashCode 方法。我想這個結(jié)果還是有點意外的,因為我們知道 HashMap 存放的是引用類型,我們在外面把 key 更新了,那也就是說 HashMap 里面的 key 也更新了,也就是這個 key 的 hashCode 返回值也會發(fā)生變化。這個時候 key 的 hashCode 和 HashMap 對于元素的 hashCode 肯定一樣,equals也肯定返回true,因為本來就是同一個對象,那為什么不能返回正確的值呢?

測試案例

這里有 2 個案例,一個是 Person 類,還有一個是 Student 類,我們來驗證下以上的觀點(附帶結(jié)論):

  • 修改了對象屬性是否會改變它的 hashcode => 是的
  • 在 HashMap 里存取的時候是否會受到修改屬性影響取值 => 取值為 null
package tech.luxsun.interview.luxinterviewstarter.collection;
?
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.HashMap;
?
/**
?* @author Lux Sun
?* @date 2021/4/22
?*/
public class MapDemo0 {
?
? ? public static void main(String[] args) {
? ? ? ? HashMap<Object, Object> map = new HashMap<>();
?
? ? ? ? // Person Case
? ? ? ? Person p = new Person("Bob", 12);
? ? ? ? map.put(p, "person");
? ? ? ? System.out.println(p.hashCode());
? ? ? ? System.out.println(map.get(p));
?
? ? ? ? p.setAge(13);
? ? ? ? System.out.println(p.hashCode());
? ? ? ? System.out.println(map.get(p));
?
? ? ? ? // Student Case
? ? ? ? Student stu = new Student("Bob", 12);
? ? ? ? map.put(stu, "student");
? ? ? ? System.out.println(stu.hashCode());
? ? ? ? System.out.println(map.get(stu));
?
? ? ? ? stu.setAge(13);
? ? ? ? System.out.println(stu.hashCode());
? ? ? ? System.out.println(map.get(stu));
? ? }
}
?
@Data
@AllArgsConstructor
@NoArgsConstructor
class Person {
? ? private String name;
? ? private Integer age;
?
? ? public int hashCode() {
? ? ? ? return 123456;
? ? }
}
?
@Data
@AllArgsConstructor
@NoArgsConstructor
class Student {
? ? private String name;
? ? private Integer age;
}

輸出結(jié)果

123456
person
123456
person
71154
student
71213
null

源碼

hashCode 源碼

public int hashCode() {
? ? int PRIME = true;
? ? int result = 1;
? ? Object $age = this.getAge();
? ? int result = result * 59 + ($age == null ? 43 : $age.hashCode());
? ? Object $name = this.getName();
? ? result = result * 59 + ($name == null ? 43 : $name.hashCode());
? ? return result;
}

map.get 源碼

/**
?* Returns the value to which the specified key is mapped,
?* or {@code null} if this map contains no mapping for the key.
?*
?* <p>More formally, if this map contains a mapping from a key
?* {@code k} to a value {@code v} such that {@code (key==null ? k==null :
?* key.equals(k))}, then this method returns {@code v}; otherwise
?* it returns {@code null}. ?(There can be at most one such mapping.)
?*
?* <p>A return value of {@code null} does not <i>necessarily</i>
?* indicate that the map contains no mapping for the key; it's also
?* possible that the map explicitly maps the key to {@code null}.
?* The {@link #containsKey containsKey} operation may be used to
?* distinguish these two cases.
?*
?* @see #put(Object, Object)
?*/
public V get(Object key) {
? ? Node<K,V> e;
? ? return (e = getNode(hash(key), key)) == null ? null : e.value;
}
?
?
/**
?* Computes key.hashCode() and spreads (XORs) higher bits of hash
?* to lower. ?Because the table uses power-of-two masking, sets of
?* hashes that vary only in bits above the current mask will
?* always collide. (Among known examples are sets of Float keys
?* holding consecutive whole numbers in small tables.) ?So we
?* apply a transform that spreads the impact of higher bits
?* downward. There is a tradeoff between speed, utility, and
?* quality of bit-spreading. Because many common sets of hashes
?* are already reasonably distributed (so don't benefit from
?* spreading), and because we use trees to handle large sets of
?* collisions in bins, we just XOR some shifted bits in the
?* cheapest possible way to reduce systematic lossage, as well as
?* to incorporate impact of the highest bits that would otherwise
?* never be used in index calculations because of table bounds.
?*/
static final int hash(Object key) {
? ? int h;
? ? return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
?
/**
?* Implements Map.get and related methods
?*
?* @param hash hash for key
?* @param key the key
?* @return the node, or null if none
?*/
final Node<K,V> getNode(int hash, Object key) {
? ? Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
? ? if ((tab = table) != null && (n = tab.length) > 0 &&
? ? ? ? (first = tab[(n - 1) & hash]) != null) {
? ? ? ? if (first.hash == hash && // always check first node
? ? ? ? ? ? ((k = first.key) == key || (key != null && key.equals(k))))
? ? ? ? ? ? return first;
? ? ? ? if ((e = first.next) != null) {
? ? ? ? ? ? if (first instanceof TreeNode)
? ? ? ? ? ? ? ? return ((TreeNode<K,V>)first).getTreeNode(hash, key);
? ? ? ? ? ? do {
? ? ? ? ? ? ? ? if (e.hash == hash &&
? ? ? ? ? ? ? ? ? ? ((k = e.key) == key || (key != null && key.equals(k))))
? ? ? ? ? ? ? ? ? ? return e;
? ? ? ? ? ? } while ((e = e.next) != null);
? ? ? ? }
? ? }
? ? return null;
}

總之

可以看到先取得了一個table,這個table實際上是個數(shù)組。然后在table里面找對應(yīng) key 的value。找的標(biāo)準(zhǔn)就是hash等于傳入?yún)?shù)的hash, 并且滿足另外兩個條件之一:k = e.key,也就是說他們是同一個對象,或者傳入的 key 的equal目標(biāo)的 key 。我們的問題出在那個hash(key.hashCode()),可以看到 HashMap 在存儲元素時是把 key 的 hashCode 再做了一次hash。得到的hash將最終作為元素存儲位置的依據(jù)。對應(yīng)到我們的情況:第一次存儲時,hash函數(shù)采用key.hashCode作為參數(shù)得到了一個值,然后根據(jù)這個值把元素存到了某個位置。

當(dāng)我們再去取元素的時候,key.hashCode的值已經(jīng)出現(xiàn)了變化,所以這里的hash函數(shù)結(jié)果也發(fā)生了變化,所以當(dāng)它嘗試去獲得這個 key 的存儲位置時就不能得到正確的值,導(dǎo)致最終找不到目標(biāo)元素。要想能正確返回,很簡單,把Person類的 hashCode 方法改一下,讓它的 hashCode 不依賴我們要修改的屬性,但實際開發(fā)中肯定不能這么干,我們總是希望當(dāng)兩個對象的屬性不完全相同時能返回不同的 hashCode 值。

所以結(jié)論就是當(dāng)把對象放到 HashMap 后,不要去修改 key 的屬性,除非你重寫了該實體類的 hashCode 方法不受屬性限制。

最后

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot + Mybatis增刪改查實戰(zhàn)記錄

    SpringBoot + Mybatis增刪改查實戰(zhàn)記錄

    這篇文章主要給大家介紹了關(guān)于SpringBoot + Mybatis增刪改查的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • SpringBoot整合mysql、postgres及sqlserver實現(xiàn)多數(shù)據(jù)源配置實戰(zhàn)案例

    SpringBoot整合mysql、postgres及sqlserver實現(xiàn)多數(shù)據(jù)源配置實戰(zhàn)案例

    在工作中業(yè)務(wù)的發(fā)展或業(yè)務(wù)數(shù)據(jù)隔離的場景下,通常需要一個項目中引入多個數(shù)據(jù)源,但SpringBoot默認(rèn)的自動化配置是單數(shù)據(jù)源的,這篇文章主要給大家介紹了關(guān)于SpringBoot整合mysql、postgres及sqlserver實現(xiàn)多數(shù)據(jù)源配置的相關(guān)資料,需要的朋友可以參考下
    2023-12-12
  • Java 泛型有哪些好處詳解

    Java 泛型有哪些好處詳解

    這篇文章主要介紹了 Java 泛型有哪些好處詳解的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • java利用oss實現(xiàn)下載功能

    java利用oss實現(xiàn)下載功能

    這篇文章主要為大家詳細(xì)介紹了java利用oss實現(xiàn)下載功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • Java單元測試Mockito的使用詳解

    Java單元測試Mockito的使用詳解

    Mockito是一個強(qiáng)大的mock工具,本文將重點講述Mockito的基本使用及注意事項,以及Controller測試用例,本文通過示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2021-07-07
  • jar命令修改jar包中的application.yml配置文件

    jar命令修改jar包中的application.yml配置文件

    本文主要介紹了jar命令修改jar包中的application.yml配置文件,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • Struts2學(xué)習(xí)筆記(2)-路徑問題解決

    Struts2學(xué)習(xí)筆記(2)-路徑問題解決

    本文主要介紹Struts2的路徑問題,盡量不要使用相對路徑,使用相對路徑會讓路徑問題變得很繁瑣很麻煩,推薦使用絕對路徑,希望能給大家做一個參考。
    2016-06-06
  • Maven中dependency和plugins的繼承與約束

    Maven中dependency和plugins的繼承與約束

    這篇文章主要介紹了Maven中dependency和plugins的繼承與約束,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 關(guān)于jdk環(huán)境變量的配置方式解讀

    關(guān)于jdk環(huán)境變量的配置方式解讀

    這篇文章主要介紹了關(guān)于jdk環(huán)境變量的配置方式解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • Spring中事務(wù)用法示例及實現(xiàn)原理詳解

    Spring中事務(wù)用法示例及實現(xiàn)原理詳解

    這篇文章主要給大家介紹了關(guān)于Spring中事務(wù)用法示例及實現(xiàn)原理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11

最新評論