HashSet<T>类主要是设计用来做高性能集运算的,例如对两个集合求交集、并集、差集等。集合中包含一组不重复出现且无特性顺序的元素。
2、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算法不唯一)
*/
@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集合中单独删除当前对象,从而造成内存泄漏。