HashSet<T>的一些特性如下:
1、HashSet<T>中的值不能重复且没有顺序。2、HashSet<T>的容量会按需自动添加。
下面是使用 Java HashSet 时要注意的一些地方:
package com.swsx.hashCode; import java.util.HashSet; import java.util.Iterator; import java.util.Set; /** * 使用HashMap要注意的一些问题 * @author Administrator * */ public class TestHashSet { public static void main(String[] args){ Person p1 = new Person("张三",21); Person p2 = new Person("李四",22); Person p3 = new Person("张三",21); Set<Person> persons = new HashSet<Person>(); persons.add(p1); persons.add(p2); persons.add(p3); /* * HashSet是按hashCode来存储元素的,如果两个元素的hashCode相同且equals为true,则只存一个元素, * Person的hashCode和equals方法已重写,由于p1和p3的hashCode相同且equals,所以p3没有被存入。 * 如果不重写hashCode,而只重写equals方法,则会造成HashSet存储重复的元素。 * */ System.out.println("HashSet中有:" + persons.size() + "个元素:"); Iterator<Person> iterator = persons.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } if (persons.contains(p1)) { System.out.println("HashSet中有元素"+ p1); }else{ System.out.println("HashSet中没有元素"+ p1); } /* * 当改变元素值时,hashCode也变了. */ System.out.println("\np1改变前的hashCode:" + p1.hashCode()); p1.setName("小武"); System.out.println("p1改变后的hashCode:" + p1.hashCode() + "\n"); System.out.println("HashSet中有:" + persons.size() + "个元素:"); iterator = persons.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } /* * HashSet是按元素的hashCode存取的,当改变元素值时,hashCode也变了, * 造成查找元素时的hashCode和存储时的hashCode不一致,结果就找不到元素了。 * 当我们遍历集合时,要查找的元素确实存在,只不过仍是按原来元素的hashCode存储的, * 但查找时却是按新的hashCode来找的。 */ if (persons.contains(p1)) { System.out.println("HashSet中有元素"+ p1); }else{ System.out.println("HashSet中没有元素"+ p1); } /* * 改回原来的元素值时,hashCode也改回来了,这时查找时的hashCode和 * 存储时的hashCode一致,元素就找到了了。 */ p1.setName("张三"); System.out.println("\np1改回来后的hashCode:" + p1.hashCode()); System.out.println("HashSet中有:" + persons.size() + "个元素:"); iterator = persons.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } if (persons.contains(p1)) { System.out.println("HashSet中有元素"+ p1); }else{ System.out.println("HashSet中没有元素"+ p1); } } } /** * 用于测试HashSet的类 * @author Administrator * */ class Person{ private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } /** * 重写父类hashCode方法(hash算法不唯一) */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } /** * 重写父类的equals方法 */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (age != other.age) 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 "Person [name=" + name + ", age=" + age + "]"; } } /*输出如下: HashSet中有:2个元素: Person [name=张三, age=21] Person [name=李四, age=22] HashSet中有元素Person [name=张三, age=21] p1改变前的hashCode:776501 p1改变后的hashCode:759683 HashSet中有:2个元素: Person [name=小武, age=21] Person [name=李四, age=22] HashSet中没有元素Person [name=小武, age=21] p1改回来后的hashCode:776501 HashSet中有:2个元素: Person [name=张三, age=21] Person [name=李四, age=22] HashSet中有元素Person [name=张三, age=21] */
总结:
1.如果一个类重写的equals方法,那么也最好重写hashCode方法,尤其是要使用与hash算法有关的集合(如HashSet、HashMap)存储对象时,这是最佳实践。
2.当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法中使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,从而造成内存泄漏。