Java 7之集合类型第6篇 - Set集合的实现(一)

2014-11-24 02:45:34 · 作者: · 浏览: 2

Set接口中定义了一些Set常见的操作,与Collection接口中定义的方法差不多。AbstractSet抽象类中只实现了equals()、hashCode()和removeAll()方法,非常简单,有兴趣的读者可以自己去查看。


1、HashSet


HashSet类的特点:能够快速定位集合中的元素、集合中的元素无序(这里所谓的无序并不是完全无序,只是不像List集合按对象的插入顺序保存对象)。
有了HashMap的实现,则HashSet的实现非常简单,只需要将Set中的元素做为Map中的key值来保存即可。

public class HashSet
  
      extends AbstractSet
   
     implements Set
    
     , Cloneable, java.io.Serializable{ private transient HashMap
     
       map; // 使用map的key来保存Set元素 private static final Object PRESENT = new Object();// 值为一个Object对象 public HashSet() { map = new HashMap<>(); } /** * Constructs a new set containing the elements in the specified * collection. The HashMap is created with default load factor * (0.75) and an initial capacity sufficient to contain the elements in * the specified collection. */ public HashSet(Collection
       c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); } // 省略其他构造函数 }
     
    
   
  
    public Iterator
  
    iterator() {     // 循环HashMap中的key值
        return map.keySet().iterator();
    }
    public boolean contains(Object o) { // 查找HashMap中的key值
        return map.containsKey(o);
    }
    public boolean add(E e) {           // key为Set中要添加的元素,值为一个空的Object对象
        return map.put(e, PRESENT)==null;
    }
  

由HashSet类实现的Set集合中的对象必须是惟一的,因此需要添加到由HashSet类实现的Set集合中的对象,需要重新实现equals()方法,从而保证插入集合中对象的标识的惟一性。

由HashSet类实现的Set集合的排列方式为按照哈希码排序,根据对象的哈希码确定对象的存储位置,因此需要添加到由HashSet类实现的Set集合中的对象,还需要重新实现hashCode()方法,从而保证插入集合中的对象能够合理地分布在集合中,以便于快速定位集合中的对象。

public class Person{
	private String name;
	private long id_card;
	public Person(String name,long id_card){
		this.name = name;
		this.id_card = id_card;
	}
	public long getId_card(){
		return id_card;
	}
	public void setId_card(long id_card){
		this.id_card = id_card;
	}
	public String getName(){
		return name;
	}
	public void setName(String name){
		this.name = name;
	}
	public int hashCode(){//重新实现hashCode()方法
		final int PRIME = 31;
		int result = 1;
		result = PRIME*result+(int)(id_card^(id_card>>>32));
		result = PRIME*result+((name ==null) 0:name.hashCode());
		return result;
	}
	public boolean equals(Object obj){//重新实现equals()方法
		if(this == obj){
			return true;
		}
		if(obj == null){
			return false;
		}
		if(getClass()!=obj.getClass()){
			return false;
		}
		final Person other = (Person)obj;
		if(id_card!=other.id_card){
			return false;
		}
		if(name == null){
			if(other.name != null){
				return false;
			}
		}
		else if(!name.equals(other.name)){
			return false;
		}
		return true;
	}
}
编写测试程序:

public class TestSet{
	public static void main(String args[]){
		Set
  
    hashSet = new HashSet
   
    (); hashSet.add(new Person("马先生",22015)); hashSet.add(new Person("李小姐",22018)); hashSet.add(new Person("李先生",22020)); Iterator
    
      it = hashSet.iterator(); while(it.hasNext()){ Person person = it.next(); System.out.println(person.getName()+" "+person.getId_card()); } } }
    
   
  
程序的运行结果如下:
李小姐 22018
李先生 22020
马先生 22015
如果既想保留HashSet类快速定位集合中对象的优点,又想让集合中的对象按插入的顺序保存,可以通过HashSet类的子类LinkedHashSet实现Set集合。

2、LinkedHashSet


LinkedHashSet,顾名思义,就是在Hash的实现上添加了Linked的支持。对于LinkedHashSet,在每个节点上通过一个链表串联起来,这样,就可以保证确定的顺序。对于希望有常量复杂度的高效存取性能要求、同时又要求排序的情况下,可以直接使用LinkedHashSet。

它实现了Set接口。存入Set的每个元素必须是唯一的,因为Set不保存重复元素。但是Set接口不保证维护元素的次序。LinkedHashSet具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的顺序),于是在使用迭代器便利Set时,结果会按元素插入的次序显示。

在HashSet中有一个构造方法,如下: