Set集合的应用

Set集合

  1. Set集合中的对象无排列顺序,且没有重复的对象。可以把Set集合理解为一个口袋,往里面丢的对象是无顺序的。
  2. 对Set集合中成员的访问和操作是通过对集合中对象的引用进行的,所以Set集合不能有重复对象(包括Set的实现类)。
  3. Set判断集合中两个对象相同不是使用"=="运算符,而是根据equals方法。每次加入一个新对象时,如果这个新对象和当前Set中已有对象进行equals方法比较都返回false时,则允许添加对象,否则不允许。

Set集合的应用

1.HashSet
HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。
HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。
HashSet 具有以下特点:

  1. 不能保证元素的排列顺序
  2. HashSet 不是线程安全的
  3. 集合元素可以是 null
  4. HashSet访问集合元素时也是根据元素的HashCode值来快速定位的。

当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。
如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。

import java.util.HashSet;
import java.util.Iterator;

public class SetDemo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		HashSet<String> h = new HashSet<String>();
		/*
		 * boolean add(E e) 将指定的元素添加到此集合(如果尚未存在)。  
		 */
		h.add("aa");
		h.add("bb");
		h.add("cc");
		System.out.println("集合h:"+h);//输出:集合h:[aa, bb, cc]
		/*
		 * boolean isEmpty() 如果此集合不包含元素,则返回 true 。  
		 */
		System.out.println("集合是否为空:"+h.isEmpty());//输出:集合是否为空:false
		/*
		 * boolean contains(Object o) 如果此集合包含指定的元素,则返回 true 。  
		 */
		System.out.println("集合中是否包含“aa”:"+h.contains("aa"));
		//输出:集合中是否包含“aa”:true
		/*
		 * int size() 返回此集合中的元素数(其基数)。  
		 */
		System.out.println("集合中元素个数:"+h.size());//输出:集合中元素个数:3
		/*
		 * boolean remove(Object o) 如果存在,则从该集合中删除指定的元素。 
		 */
		//删除元素bb
		h.remove("bb");
		System.out.println("集合中元素:"+h);//输出:集合中元素:[aa, cc]
		
		/*
		 * Iterator<E> iterator() 返回此集合中元素的迭代器。  
		 */
		Iterator<String> i = h.iterator();
		while(i.hasNext()){
			String s = i.next();
			System.out.println("迭代器遍历集合元素:"+s);
			/*
			 * 输出:
			 * 迭代器遍历集合元素:aa
			 * 迭代器遍历集合元素:cc
			 */
		}
		/*
		 * void clear() 从此集合中删除所有元素。  
		 */
		//清空集合中元素
		h.clear();
		System.out.println("集合中的元素:"+h);//输出:集合中的元素:[]
		System.out.println("集合中元素个数:"+h.size());//输出:集合中元素个数:0

	}

}

import java.util.HashSet;

public class SetDemo1 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		HashSet h = new HashSet();
		h.add(new A());
		h.add(new A());
		System.out.println(h);
		//输出:[set.A@15db9742, set.A@6d06d69c]
		/*
		 * 说明:两个元素不一样,hashcode值也不一样
		 */
		h.add(new B());
		h.add(new B());
		System.out.println(h);
		//输出:[set.B@1, set.B@1, set.A@15db9742, set.A@6d06d69c]
		/*
		 * 说明:两个元素一样,hashcode值不一样
		 */
		h.add(new C());
		h.add(new C());
		System.out.println(h);
		//输出:[set.B@1, set.B@1, set.C@2, set.A@15db9742, set.A@6d06d69c]
		/*
		 * 说明:同一个元素
		 */
	}
}

class A {
  public boolean equals(Object obj) {
      return true;
  }
}

class B {
  public int hashCode() {
      return 1;
  }
}

class C{
  public int hashCode(){
      return 2;
  }
  public boolean equals(Object obj){
      return true;
  }
}


可以看出,HashSet集合通过hashCode()采用hash算法来决定元素的存储位置,如上输出。输出中添加的B类的对象是同一个,所以这并不符合Set集合没有重复的对象的规则,所以如果需要把某个类的对象保存到HashSet集合时,在重写这个类的equlas()方法和hashCode()方法时,应该尽量保证两个对象通过equals()方法比较返回true时,它们的hashCode()方法返回值也相等。

2.LinkedHashSet
LinkedHashSet 是 HashSet 的子类
LinkedHashSet 集合根据元素的 hashCode 值来决定元素的存储位置,但它同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。
LinkedHashSet 性能插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。
LinkedHashSet 不允许集合元素重复。

import java.util.HashSet;
import java.util.LinkedHashSet;

public class SetDemo2 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		HashSet hashSet = new HashSet();
	    hashSet.add("hello");
	    hashSet.add("world");
	    hashSet.add("hashSet");
	    System.out.println(hashSet);
	    //输出:[world, hashSet, hello]
	    /*
	     * 根据元素的 hashCode 值来决定元素的存储位置
	     */

	    LinkedHashSet linkedHashSet = new LinkedHashSet();
	    linkedHashSet.add("Hello");
	    linkedHashSet.add("World");
	    linkedHashSet.add("linkedHashSet");
	    System.out.println(linkedHashSet);
	    //输出:[Hello, World, linkedHashSet]
	    /*
	     * 根据元素的 hashCode 值来决定元素的存储位置,
	     * 但同时使用链表维护元素的次序,元素以插入顺序保存。
	     */

	    //删除 Hello
	    linkedHashSet.remove("Hello");
	    //重新添加 Hello
	    linkedHashSet.add("Hello");
	    System.out.println(linkedHashSet);
	    //输出:[World, linkedHashSet, Hello]
	        
	    //添加World
	    linkedHashSet.add("World");
	    System.out.println(linkedHashSet);
	    //输出:[World, linkedHashSet, Hello]
	    /*
	     * 添加失败,LinkedHashSet 不允许集合元素重复。
	     */
	}

}

3.TreeSet
TreeSet 是 SortedSet 接口的实现类。
TreeSet集合是用来对元素进行排序的,采用红黑树的数据结构来存储集合元素,且可以保证元素的唯一。
TreeSet 支持两种排序方法:自然排序和定制排序。

  1. 自然排序:调用集合元素的compareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序排序。
  2. 定制排序:实现定制排序,则可以通过Comparator接口里的int compare(T o1, T o2)方法,该方法用于比较大小。

默认情况下,TreeSet 采用自然排序。

import java.util.Iterator;
import java.util.NavigableSet;
import java.util.SortedSet;
import java.util.TreeSet;

public class SetDemo3 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TreeSet t = new TreeSet();
		//添加Integer对象
		t.add(-2);
		t.add(0);
		t.add(-5);
		t.add(3);
		t.add(7);
		System.out.println("TreeSet集合:"+t);
		//输出:TreeSet集合:[-5, -2, 0, 3, 7]
		/*
		 * 说明TreeSet集合能对元素进行自动排序
		 */
		
		/*
		 * Iterator<E> descendingIterator() 
		 * 以降序返回该集合中的元素的迭代器。  
		 */
		Iterator<Integer> i = t.descendingIterator();
		while(i.hasNext()){
			int a = i.next();
			System.out.print(" "+a);
			//输出: 7 3 0 -2 -5
		}
		System.out.println();
		
		/*
		 * NavigableSet<E> descendingSet() 
		 * 返回此集合中包含的元素的反向排序视图。 
		 */
		NavigableSet<Integer> na = t.descendingSet();
		System.out.println("反向排序视图:"+na);
		//输出:反向排序视图:[7, 3, 0, -2, -5]
		
		/*
		 * E first() 返回此集合中当前的第一个(最小)元素。  
		 */
		System.out.println("第一个元素(最小元素):"+t.first());
		//输出:第一个元素(最小元素):-5
		
		/*
		 * E last() 返回此集合中当前的最后(最大)元素。  
		 */
		System.out.println("最后元素(最大元素):"+t.last());
		//输出:最后元素(最大元素):7
		
		/*
		 * SortedSet<E> headSet(E toElement) 
		 * 返回此集合的部分的视图,其元素小于 toElement 。  
		 */
		SortedSet<Integer> st = t.headSet(1);
		System.out.println("小于1的元素:"+st);
		//输出:小于1的元素:[-5, -2, 0]
		
		/*
		 * E higher(E e) 
		 * 返回大于给定元素的该集合中的最小元素,如果没有此元素则返回 null 。  
		 */
		System.out.println("大于1的最小元素:"+t.higher(1));
		
		/*
		 * E lower(E e) 
		 * 返回这个集合中小于给定的元素的最大的元素,如果没有这样的元素,则返回 null 。  
		 */
		System.out.println("小于1的最大的元素:"+t.floor(1));//输出:0
		/*
		 * E floor(E e) 
		 * 返回此集合中小于或等于给定元素的最大的元素,如果没有这样的元素,则返回 null 。  
		 */
		System.out.println("小于1的最大的元素:"+t.floor(1));//输出:0
		
		/*
		 * NavigableSet<E> subSet(E fromElement, boolean a, E toElement, boolean b) 
		 * 返回该集合的部分的视图,其元素的范围从 fromElement到 toElement 。  
		 */
		NavigableSet<Integer> nav1 = t.subSet(-2, true, 3, true);
		System.out.println(nav1);
		//输出:[-2, 0, 3]
		NavigableSet<Integer> nav2 = t.subSet(-2, true, 3, false);
		System.out.println(nav2);
		//输出:[-2, 0]
		
		/*
		 * SortedSet<E> subSet(E fromElement, E toElement) 
		 * 返回此集合的部分的视图,其元素的范围从 fromElement (含)到 toElement(不含)。  
		 */
		SortedSet<Integer> so = t.subSet(-2, 3);
		System.out.println(so);
		//输出:[-2, 0]
		
	}

}

Set集合总结

  1. HashSet的性能比TreeSet好(包括添加、查询元素等操作),因为TreeSet需要额外的红黑树算法来维护集合元素的次序。
    当需要一个始终保持排序的Set时,才使用TreeSet,否则使用HashSet。
  2. 对于LinkedHashSet,普通的插入、删除操作比HashSet要略慢一点,因为维护链表会带来的一定的开销。好处是,遍历比HashSet会更快
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值