使用 Java HashSet 时要注意的一些地方

来源:互联网 发布:淘宝黑搜原理 编辑:程序博客网 时间:2024/05/19 04:05
HashSet<T>类主要是设计用来做高性能集运算的,例如对两个集合求交集、并集、差集等。集合中包含一组不重复出现且无特性顺序的元素。

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算法不唯一) */@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + age;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}/** * 重写父类的equals方法 */@Overridepublic 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;}@Overridepublic 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:776501p1改变后的hashCode:759683HashSet中有:2个元素:Person [name=小武, age=21]Person [name=李四, age=22]HashSet中没有元素Person [name=小武, age=21]p1改回来后的hashCode:776501HashSet中有: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集合中单独删除当前对象,从而造成内存泄漏。

0 0