1. 程式人生 > >HashSet為何會加入重複元素

HashSet為何會加入重複元素

最近準備換一份新工作,為了在接下來的面試中能夠取得一個好成績,因此準備將學過的java有關的知識整體的梳理一下。但是在看到HashSet的時,閒著無聊所做的測試發現原本以為的成員不會重複的HashSet卻成功添加了重複的元素。程式碼如下:

package com.holmes.learn.jihe;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class MyData {
	
	public static void main(String[] args) {
		
		Set<MyData> set = new HashSet<>();
		
		MyData data1 = new MyData("1", "1");
		MyData data2 = new MyData("2", "2");
		MyData data3 = new MyData("1", "1");
		
		set.add(data1);
		set.add(data2);
		set.add(data3);
		
		Iterator<MyData> iterator = set.iterator();
		while (iterator.hasNext()) {
			MyData data = iterator.next();
			System.out.println(data + " " + data.hashCode());
		}
		
		System.out.println();
		
		data1.setId("4");
		set.add(data1);
		
		iterator = set.iterator();
		while (iterator.hasNext()) {
			MyData data = iterator.next();
			System.out.println(data + " " + data.hashCode());
		}
		System.out.println();
		
		set.add(data3);
		
		iterator = set.iterator();
		while (iterator.hasNext()) {
			MyData data = iterator.next();
			System.out.println(data + " " + data.hashCode());
		}
	}

	
	private String id;
	private String name;
	
	public MyData(){
		
	}
	public MyData(String id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		MyData other = (MyData) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	
	@Override
	public String toString() {
		return "MyData [id=" + id + ", name=" + name + "]";
	}
}
MyData是一個包含id和name兩個String型別的成員變數的類,並通過兩個變數的值重寫了equals和hashCode方法。第一步向HashSet中插入三個元素:
MyData data1 = new MyData("1", "1");
MyData data2 = new MyData("2", "2");
MyData data3 = new MyData("1", "1");

很顯然,根據HashSet的元素不重複可以知道第一次列印的結果為:

MyData [id=2, name=2] 2561
MyData [id=1, name=1] 2529

data1與data3的值相同,顯然data3無法新增成功。

第二步改變data1的值,再次向set中新增data1,並列印結果,發現了新增成功了。

data1.setId("4");
set.add(data1);
MyData [id=2, name=2] 2561
MyData [id=4, name=1] 2622
MyData [id=4, name=1] 2622

第三步把之前data3再次新增進去,並列印結果,發現再次新增成功。

set.add(data3);
MyData [id=2, name=2] 2561
MyData [id=4, name=1] 2622
MyData [id=1, name=1] 2529
MyData [id=4, name=1] 2622

通過以上實驗發現,HashSet中竟然出現了重複元素。這是為什麼呢?

看過jdk原始碼的都知道,HashSet元素不重複的功能是通過HashMap的key唯一來實現的。再向HashSet中新增物件時,首先通過hashCode值來判斷物件是否相同,如果不同,則直接向set中新增,相同則通過比較equals來比較元素是否相同。同時,hashSet通過hashCode的值來選擇將新增的元素放到相應的“位置”。

根據上述規則可以知道,程式碼中,第一次向set中新增data1、data2與data3時,成功添加了data1和data2,但是在修改了data1的值後再次新增的過程中,向判斷元素的hashCode值對應的“位置”是否已有元素存在,顯然是沒有的,所以新增成功了。第三步中新增data3時,計算hashCode時發現“位置”已經被佔了,接著判斷equals的值,結果為false,所以data3依然新增成功了。

總結:在使用HashSet儲存物件時,發生上述情況會導致記憶體洩漏,因此在使用時應當注意。當然,出現任何問題我們都能以我們所知道的知識來解釋問題、避免問題,並解決問題。

相關推薦

HashSet為何加入重複元素

最近準備換一份新工作,為了在接下來的面試中能夠取得一個好成績,因此準備將學過的java有關的知識整體的梳理一下。但是在看到HashSet的時,閒著無聊所做的測試發現原本以為的成員不會重複的HashSet卻成功添加了重複的元素。程式碼如下:package com.holmes.

HashSet與TreeSet對重複元素的判斷不同之處

轉:http://wlt2008-com.iteye.com/blog/1447207 HashSet 的實現其實非常簡單,它只是封裝了一個 HashMap 物件來儲存所有的集合元素,所有放入 HashSet 中的集合元素實際上由 HashMap 的 key 來儲存,而

python 刪除重複元素字典並在字典中加入重複元素次數

mylist = [{"b":1},{"b":1},{"b":1},{"b":1},{"c":2},{"c":2},{"b":1},{"b":1},{"b":1},{"c":2},{"c":2}] myset = [] for i in mylist: if not

利用 HashSet重複特性返回素組中重複元素

static void Main(string[] args) { int[] array = GetArray(new int[] { 3, 2, 32, 3, 1, 2,3 }); for

HashSet集合存入物件,去除重複元素(覆寫equals和hashCode方法)

import java.util.*; class Person { private String name; private int age; Person(String name,int a

ArrayList和HashSet如何去除重複元素

1. ArrayList去除重複元素 利用contains()方法,其內部呼叫的還是equals()方法,需要重寫equals(),自己定義元素相同的規則 import java.util.*; class ArrayListDemo2 { pub

JAVA基礎之——HashSet中是如何判斷元素是否重複

原文:http://blog.csdn.net/ning109314/article/details/17354839 HashSet不能新增重複的元素,當呼叫add(Object)方法時候,首先會呼叫Object的hashCode方法判hashCode是否已經存在,如不

HashSet中是如何判斷元素是否重複

HashSet不能新增重複的元素,當呼叫add(Object)方法時候, 首先會呼叫Object的hashCode方法判hashCode是否已經存在,如不存在則直接插入元素;如果已存在則呼叫Object物件的equals方法判斷是否返回true,如果為true則說明元素已經

jquery在ajax新加入元素後綁定事件click

path pen con art yii 例如 () click bsp 使用YII在做一個點擊小圖。能夠在彈出窗體中顯示大圖的功能的時候,發現。GridView首頁面的列表項按點擊時一切正常,但按下了下一頁後。 再點擊小圖,就不起作用了。原來,這是GridView

更改Windows Update設置時,為何提示“某些設置由你的系統管理員管理”?

http window con 備份 計算機 list alt+ text 應該 親測有效 及時進行更新是保證系統正常運行的一個有效措施。可為什麽當我們進入“控制面板->Windows Update”手動修改 Windows Update 的設

裁員1000人!魅族為何愈發衰落?

魅族據媒體報道3月29日PingWest品玩從接近魅族的消息人士處獲悉,魅族或將會迎來新一輪裁員人員可能會達上千人,官方最快將於下周宣布裁員消息。 看到這則消息的時候,我一直是不斷嘆息的。畢竟在前幾年,我還是一個魅族的粉絲。雖然不是鐵桿擁躉,但也是為自己和家人買過多部魅族手機。小圓點、腰圓鍵、mback、fl

人工智能時代Python為何是最佳選擇?

Python學習 Python入門 Python基礎 Python開發 人工智能時代Python為何會是最佳選擇?隨著移動互聯網、物聯網的加速發展,人類將迎來了人工智能的時代。無論是戰勝了圍棋大師的AI,還是IBM的超級電腦“沃森”都讓人工智能在科技圈狠狠的火了一把。國內大佬也相繼加持人工智能

Rsync為何是運維人員必備技能之一?

Linux運維 Linux學習 Linux基礎 Linux入門 Rsync是一款開源的、快速的、多功能的、可實現全量及增量的本地或遠程數據同步備份的優秀工具,也是運維人員必備技能之一。那Rsync有什麽特點使得它有如此的地位呢?1.Rsync有啥特性?1)支持拷貝特殊文件,比如連接文件、設備等

MongoDB 是由C++編寫的?那麽為何在Python領域中風生水起呢?

name 內嵌 個數 dfs rip res 直接 reat god MongoDB 是一個面向文檔存儲的數據庫,操作起來比較簡單和容易。 你可以在MongoDB記錄中設置任何屬性的索引 (如:FirstName="Sameer",Address="8 Gandh

集合的全排列(可包含重複元素)

全排列如果按字典順序排好的話,我們知道其中的一個序列,就能推出下一個序列。比如說集合{1,2,3}的全排列按字典排序後如下: 1  2   3 1  3   2 2  1   3 2   3  1

子集生成之增量構造法(允許有重複元素)

假設集合S中有n個元素,它的子集的元素個數可以為1至n個,這個問題等價於有n個桶,按順序擺好並編號0~n-1,然後我們依次走到這n個桶面前,此時我們可以決定不放元素,或者放一個元素,因為集合是無序的(集合{1,2,3}和{2,1,3}相同),所以我們可以事先將S中的元素排序,這樣我們走到編號為s

重複元素的組合

字典序從小到大 #include<cstdio> #include<algorithm> using namespace std; bool vis[30]; int n,r,arr[30],a[30],had; bool check(int now) {

leetcode219:存在重複元素

思想: 1.先判斷nums是否為空,為空則返回false。再判斷k是否等於0,為0則返回false。 2.由於range函式後面的範圍取不到則需要k+1,然後需要判斷加1後的k有什麼超過nums的長度。若超過,則選擇nums的長度作為k值。 3.定義了一個雙向佇列windows來儲存元素

刪除重複元素

/*已知一個單鏈表中的元素按值非遞減有序排列,編寫演算法刪除表中多餘的值相等的元素,即有多個相等結點時,只保留其中一個結點*/ typedef struct{ int data; struct LNode *next; }LNode,*LinkList; void DeleteEqual(Linklist

poj3421 X-factor Chains(重複元素的全排列)

poj3421 X-factor Chains 題意:給定正整數$x(x<=2^{20})$,求$x$的因子組成的滿足任意前一項都能整除後一項的序列的最大長度,以及滿足最大長度的子序列的個數。 顯然最大長度就是$x$的質因數個數(一個一個加上去鴨) 而滿足最大長度的子序列個數.... 這不就是可