Java 集合 Set HashSet

參考連接:http://blog.csdn.net/solafy/article/details/52960777java

1. Set 一般存儲String常量,一般使用HashSet<String>, HashSet內部實現是由HashMap,所以有比較高的查詢和讀取性能。HashSet不是線程安全的,不能保證順序,HashSet中的元素能夠爲Null.安全

HashSet如何保證元素不重複呢,HashSet須要同時經過equals和HashCode方法判斷兩個元素是否相等。ide

查看另外一篇博客關於String的equals方法和hashCode方法的重寫。性能

http://www.javashuo.com/article/p-pyagrabt-cw.htmlthis

即兩個元素的的equals方法比較結果相等,而且他們的hashCode值也同樣,那這兩個元素就相等,也就是重複的元素。.net

若是重寫了equals方法但不重寫hashCode方法,即equals方法比較結果爲true,但HashSet認爲是兩個不一樣的元素,就會存儲重複的數據。以下面的例子所示,person1和person2是相同的元素,可是由於註釋了hashCode方法,他們的hashCode值不同,所以HashSet認爲他們是不一樣的元素,所以size大小是2.線程

package com.example.demo;

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

public class Person {
	
	private Integer id;
	private String username;
	private Integer age;
	
	
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public Person(Integer id, String username, Integer age) {
		this.id = id;
		this.username = username;
		this.age = age;
	}
	
	/*public int hashCode() {
		final int prime = 31;
		int result =1;
		result = prime * 31 + ((id == null) ? 0 : id.hashCode());
		return result;
	}*/
	
	public boolean equals(Object obj) {
		if(this == obj) {
			return true;
		}
		
		if(obj == null) {
			return false;
		}
		
		if(obj instanceof Person) {
			Person person = (Person) obj;
			if(id == person.getId() && username.equals(person.getUsername()) && age == person.getAge()) {
				return true;
			}
			return false;
		}
		
		return false;
		
		
	}
	@Override
	public String toString() {
		return "Person [id=" + id + ", username=" + username + ", age=" + age + "]";
	}
	
	
	public static void main(String[] args) {
		Person person1 = new Person(1, "Jerry", 28);
		Person person2 = new Person(1, "Jerry", 28);
		Set<Person> persons = new HashSet<Person>();
		persons.add(person1);
		persons.add(person2);
		
		System.out.println("person1 equals person2: "+person1.equals(person2)); // true
		System.out.println("person1 hashCode: "+person1.hashCode()); // 2018699554
		System.out.println("person2 hashCode: "+person2.hashCode()); // 1311053135
		System.out.println("persons size:"+persons.size()); // 2
	}
	

}

下面咱們把hashCode方法取消註釋,重寫運行,咱們看到person1和person2的equals方法返回true,並且他們的hashCode都是962,size大小是1,所以取消了重複的數據。code

person1 equals person2: true
person1 hashCode: 962
person2 hashCode: 962
persons size:1

若是HashCode相等,可是equals方法返回false,則HashSet認爲這是兩個不一樣的元素,可是他們的hashCode值同樣,所以它們存儲在內存中相同的位置,這就形成了hash衝突,以下面的例子。blog

package com.example.demo;

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

public class Person {
	
	private Integer id;
	private String username;
	private Integer age;
	
	
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public Person(Integer id, String username, Integer age) {
		this.id = id;
		this.username = username;
		this.age = age;
	}
	
	public int hashCode() {
		final int prime = 31;
		int result =1;
		result = prime * 31 + ((id == null) ? 0 : id.hashCode());
		return result;
	}
	
	public boolean equals(Object obj) {
		if(this == obj) {
			return true;
		}
		
		if(obj == null) {
			return false;
		}
		
		if(obj instanceof Person) {
			Person person = (Person) obj;
			if(id == person.getId() && username.equals(person.getUsername()) && age == person.getAge()) {
				return true;
			}
			return false;
		}
		
		return false;
		
		
	}
	@Override
	public String toString() {
		return "Person [id=" + id + ", username=" + username + ", age=" + age + "]";
	}
	
	
	public static void main(String[] args) {
		Person person1 = new Person(1, "Jerry", 28);
		Person person2 = new Person(1, "Jerry", 27); // change 28 to 27
		Set<Person> persons = new HashSet<Person>();
		persons.add(person1);
		persons.add(person2);
		
		System.out.println("person1 equals person2: "+person1.equals(person2)); 
		System.out.println("person1 hashCode: "+person1.hashCode()); 
		System.out.println("person2 hashCode: "+person2.hashCode()); 
		System.out.println("persons size:"+persons.size()); 
	}
	

}

運行結果:內存

person1 equals person2: false
person1 hashCode: 962
person2 hashCode: 962
persons size:2

person1 和 person2的hashCode值同樣,但equals方法返回false, HashSet認爲是兩個不一樣的元素,所以size 是 2。這就形成了hash衝突。由於他是根據hashCode的值做爲地址存儲的,如今遇到要在相同的地址存儲不一樣的值,這就會產生衝突。解決這個Hash衝突的辦法是使用單鏈表方式保存,但這樣會影響查詢的效率。

相關文章
相關標籤/搜索