參考連接: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衝突的辦法是使用單鏈表方式保存,但這樣會影響查詢的效率。