復雜對象作為Map的key導致內存溢出問題


復雜對象作為map的key時,如果修改了對象中某些字段的值,必導致內存泄露,是因為這個節點存儲的地址未改變,但這個因為對象的字段改變導致hashcode發生改變,所以map.get(obj),map.containsKey(obj),map.remove(obj)都無法訪問到該對象,會變成死對象,稱之為內存泄露,大量的內存泄露會導致內存溢出。解決方案:要修改的對象的字段,不參與hashcode的計算,即重寫hashcode和equals方法。

 

總結:HashMap在使用可變對象作為key是一件很危險的事情,解決辦法重寫hashcode方法和equals方法

 

比較兩個對象是否相等時需要調用對象的equals()方法,即判斷對象引用所指向的對象地址是否相等,對象地址相等時,

Object類的源碼可以看出,默認的equals 判斷的是兩個對象的引用指向的是不是同一個對象;而hashcode也是根據對象地址生成一個整數數值;

 

當我們重寫一個類的 equals 方法時就應當連同重寫 hashcode 方法,並且兩個方法應滿足:

1:一致性,即:當兩個對象 equals 比較為 true,那么 hashcode 值應當相等,反之亦然,因為當兩個對象hashcode 值相等,但是 equals 比較為 false,那么在 HashMap 中會產生鏈表,影響查詢性能。

2:成對重寫,即重寫 equals 就應當重寫 hashcode。

 

為什么覆蓋equals方法時總要覆蓋hashCode方法?

因為如果不這么做的話,就違反了Object.hashCode的通用約定,導致該類無法結合所有基於散列的集合(HashMap,HashSet,HashTable)一起正常運作.

 

在應用程序執行期間,只要equals方法的比較操作用到的信息沒變,那么對這同一個對象調用多次,hashCode方法都必須始終如一的返回同一個整數.但在應用程序的多次執行中,即重新啟動后結果可以不一致.

如果兩個對象根據equals比較是相等的,那這兩個對象調用hashCode方法返回的結果必須是一樣的.

如果兩個對象根據equals比較是不相等,那這兩個對象調用hashCode方法返回的結果不一定不同.但不同的對象產生不同的hasCode,可以提高散列表的性能.

不覆蓋hashCode而違反的關鍵約定是第二條:相等的對象必須具有相等的hashCode.

如果相同的對象具有不同的hashCode,那么將對象放入hashMap中,對象會被存放到不同的桶中,當去get 時,雖然是同一個對象,但是由於生成的hashCode不同,會到不同的桶中去找,此時便找不到那個對象。

 

在程序執行期間,只要equals方法的比較操作用到的信息沒有被修改,那么對這同一個對象調用多次,hashCode方法必須始終如一地返回同一個整數。

如果兩個對象根據equals方法比較是相等的,那么調用兩個對象的hashCode方法必須返回相同的整數結果。

如果兩個對象根據equals方法比較是不等的,則hashCode方法不一定得返回不同的整數。

 

所以在不覆蓋equals方法時,使用equals方法和==的比較結果是一樣的。

 

一個Native Method方法就是一個JAVA調用非JAVA代碼的接口,native這個方法實現在C++中

 

因為 Set 存儲的是不重復的對象,依據 hashCode 和 equals 進行判斷,所以 Set 存儲的 對象必須重寫這兩個方法。

1)HashSet集合排重時,需要判斷兩個對象是否相同,對象相同的判斷可以通過hashCode值判斷,所以需要重寫hashCode()方法

2)hashset不能為一樣的,放入一個值首先判斷hashcode(類似下標)是否已經存在,然后用equals判斷是否有一樣的值。

3)如果只重寫其中一個方法的時候,向HashSet集合中添加多個對象時,所有屬性都相同時,並沒有完成想要的排重效果。hashset不能為一樣的,放入一個值首先判斷hashcode(內存中的位置)是否已經存在,然后用equals判斷是否有一樣的值。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM