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