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冲突的办法是使用单链表方式保存,但这样会影响查询的效率。

相关文章
相关标签/搜索