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

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集合中单独删除当前对象,从而造成内存泄漏。

使用 Java HashSet 时要注意的一些地方,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。