集合Set

  • 确定性:对任何对象都能判定其是否属于某一个集合;
  • 互异性:集合内每个元素都是不相同的,内容互异;
  • 无序性:集合内的顺序无关;

Java中的集合接口Set

  • HashSet(基于散列函数的集合,无序,不支持同步)
  • TreeSet(基于树结构的集合,可排序的,不支持同步)
  • LinkedHashSet(基于散列函数和双向链表的集合,可排序的,不支持同步)

HashSet

  • 基于HashMap实现的,可以容纳null元素,不支持同步
  • Set s=Collections.synchronizedSet(new HashSet(...));
  • add 添加一个元素
  • clear 清除整个HashSet
  • contains 判定是否包含一个元素
  • remove 删除一个元素
  • size 大小
  • retainsAll 计算两个集合交集
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;

public class HashSetTest {
	public static void main(String[] args) {
		HashSet<Integer> hs = new HashSet<Integer>();
		hs.add(null);
		hs.add(1000);
		hs.add(20);
		hs.add(3);
		hs.add(40000);
		hs.add(5000000);
		hs.add(3);                      //3 重复添加
		hs.add(null);                   //null重复添加
		System.out.println(hs.size());  //6
		if(!hs.contains(6))//如果不包含6,则添加6
		{
			hs.add(6);
		}
		System.out.println(hs.size());  //7
		hs.remove(4);
		System.out.println(hs.size());  //7
		//hs.clear();
		//System.out.println(hs.size());  //0
		
		System.out.println("============for循环遍历=============="); 
	    for(Integer item : hs)
	    {
	    	System.out.println(item);
	    }
	    
	    System.out.println("============测试集合交集==============");
	    
	    HashSet<String> set1 = new HashSet<String>();
	    HashSet<String> set2 = new HashSet<String>();

        set1.add("a");
        set1.add("b");
        set1.add("c");

        set2.add("c");
        set2.add("d");
        set2.add("e");

        //交集
        set1.retainAll(set2);
        System.out.println("交集是 "+set1);
        
        System.out.println("============测试多种遍历方法速度==============");
		
		HashSet<Integer> hs2 = new HashSet<Integer>();
		for(int i=0;i<100000;i++)	{
			hs2.add(i);
		}
		traverseByIterator(hs2);
		traverseByFor(hs2);		
	}
	
	public static void traverseByIterator(HashSet<Integer> hs)
	{
		long startTime = System.nanoTime();
		System.out.println("============迭代器遍历=============="); 
	    Iterator<Integer> iter1 = hs.iterator();  
	    while(iter1.hasNext()){  
	        iter1.next();  
	    }
		long endTime = System.nanoTime();
	    long duration = endTime - startTime;
	    System.out.println(duration + "纳秒");
	}
	public static void traverseByFor(HashSet<Integer> hs)
	{
		long startTime = System.nanoTime();
		System.out.println("============for-each遍历=============="); 
	    for(Integer item : hs)
	    {
	    	;
	    }
		long endTime = System.nanoTime();
	    long duration = endTime - startTime;
	    System.out.println(duration + "纳秒");
	}
}



测试结果



6
7
7
============for循环遍历==============
null
40000
3
20
6
1000
5000000
============测试集合交集==============
交集是 [c]
============测试多种遍历方法速度==============
============迭代器遍历==============
59033300纳秒
============for-each遍历==============
96651700纳秒



  • 对集合进行元素重复添加无效
  • 遍历的输出顺序与元素添加顺序无关
  • 迭代器遍历效率更高

LinkedHashSet

  • 继承HashSet,也是基于HashMap实现的,可以容纳null元素
  • 不支持同步
  • Set s = Collection.synchronizedSet(New LinkedHashSet(...));
  • 方法和HashSet基本一致
  • add,clear,contains,remove,size
  • 通过一个双向链表维护插入顺序
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;

public class LinkedHashSetTest {
	public static void main(String[] args) {
		LinkedHashSet<Integer> lhs = new LinkedHashSet<Integer>();
		lhs.add(null);
		lhs.add(1000);
		lhs.add(20);
		lhs.add(3);
		lhs.add(40000);
		lhs.add(5000000);
		lhs.add(3);                      //3 重复
		lhs.add(null);                   //null 重复
		System.out.println(lhs.size());  //6
		if(!lhs.contains(6))
		{
			lhs.add(6);
		}
		System.out.println(lhs.size());  //7
		lhs.remove(4);
		System.out.println(lhs.size());  //6
		//lhs.clear();
		//System.out.println(lhs.size());  //0
		
		System.out.println("============for循环遍历=============="); 
	    for(Integer item : lhs)
	    {
	    	System.out.println(item);
	    }
		
		LinkedHashSet<Integer> lhs2 = new LinkedHashSet<Integer>();
		for(int i=0;i<100000;i++)
		{
			lhs2.add(i);
		}
		traverseByIterator(lhs2);
		traverseByFor(lhs2);
		
	}
	
	public static void traverseByIterator(LinkedHashSet<Integer> hs)
	{
		long startTime = System.nanoTime();
		System.out.println("============迭代器遍历=============="); 
	    Iterator<Integer> iter1 = hs.iterator();  
	    while(iter1.hasNext()){  
	        iter1.next();  
	    }
		long endTime = System.nanoTime();
	    long duration = endTime - startTime;
	    System.out.println(duration + "纳秒");
	}
	public static void traverseByFor(LinkedHashSet<Integer> hs)
	{
		long startTime = System.nanoTime();
		System.out.println("============for-each遍历=============="); 
	    for(Integer item : hs)
	    {
	    	;
	    }
		long endTime = System.nanoTime();
	    long duration = endTime - startTime;
	    System.out.println(duration + "纳秒");
	}
}



测试结果



6
7
7
============for循环遍历==============
null
1000
20
3
40000
5000000
6
============迭代器遍历==============
12353400纳秒
============for-each遍历==============
9365600纳秒



  • 遍历结果和插入顺序一致
  • for-each遍历更快

TreeSet

  • 基于TreeMap实现,不可以容纳null元素,不支持同步
  • SortedSet s=Collections.synchronizedSortedSet(new TreeSet(...));//变成同步
  • add 添加一个元素
  • clear清除整个TreeSet
  • contains判断是否包含一个元素
  • remove删除一个元素
  • size大小
  • 根据compareTo方法或指定Comparator排序
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.TreeSet;

public class TreeSetTest {
	public static void main(String[] args) {
		TreeSet<Integer> ts = new TreeSet<Integer>();
		// ts.add(null);  错误,不支持null
		ts.add(1000);
		ts.add(20);
		ts.add(3);
		ts.add(40000);
		ts.add(5000000);
		ts.add(3);                      //3 重复
		System.out.println(ts.size());  //5
		if(!ts.contains(6))
		{
			ts.add(6);
		}
		System.out.println(ts.size());  //6
		ts.remove(4);
		System.out.println(ts.size());  //5
		//lhs.clear();
		//System.out.println(lhs.size());  //0
		
		System.out.println("============for循环遍历=============="); 
	    for(Integer item : ts)
	    {
	    	System.out.println(item);
	    }
	    
		TreeSet<Integer> ts2 = new TreeSet<Integer>();
		for(int i=0;i<100000;i++)
		{
			ts2.add(i);
		}
		traverseByIterator(ts2);
		traverseByFor(ts2);
		
	}
	
	public static void traverseByIterator(TreeSet<Integer> hs)
	{
		long startTime = System.nanoTime();
		System.out.println("============迭代器遍历=============="); 
	    Iterator<Integer> iter1 = hs.iterator();  
	    while(iter1.hasNext()){  
	        iter1.next();  
	    }
		long endTime = System.nanoTime();
	    long duration = endTime - startTime;
	    System.out.println(duration + "纳秒");
	}
	public static void traverseByFor(TreeSet<Integer> hs)
	{
		long startTime = System.nanoTime();
		System.out.println("============for-each遍历=============="); 
	    for(Integer item : hs)
	    {
	    	;
	    }
		long endTime = System.nanoTime();
	    long duration = endTime - startTime;
	    System.out.println(duration + "纳秒");
	}

}



输出结果:



5
6
6
============for循环遍历==============
3
6
20
1000
40000
5000000
============迭代器遍历==============
8987700纳秒
============for-each遍历==============
6676000纳秒



TreeSet按照所存储对象大小升序输出的

元素重复的判定

  • HashSet,LinkedHashSet,TreeSet的元素都只能是对象;
  • HashSet和LinkedHashSet判定元素是否重复原则:
  • 判定两个元素hashCode返回值是否相同,若不同,返回false;
  • 若两者hashCode相同,判定equals方法,若不同,返回false;否则,返回true;
  • hashCode和equals方法是所有类都有的,因为Object类有
  • TreeSet判定元素重复的原则
  • 需要元素继承自Comparable接口
  • 比较两个元素的compareTo方法

HashSet和LinkedHashSet例程:

Cat.java



class Cat
{
	private int size;
	
	public Cat(int size)
	{
		this.size = size;
	}
}



Dog.java



class Dog {
    private int size;
 
    public Dog(int s) {
        size = s;
    }      
    public int getSize() {
		return size;
	}

	public boolean equals(Object obj2)   {
    	System.out.println("Dog equals()~~~~~~~~~~~");
    	if(0==size - ((Dog) obj2).getSize()) {
    		return true;
    	} else {
    		return false;
    	}
    }
    
    public int hashCode() {
    	System.out.println("Dog hashCode()~~~~~~~~~~~");
    	return size;
    }
    
    public String toString() {
    	System.out.print("Dog toString()~~~~~~~~~~~");
        return size + "";
    }
}



Tiger.java



public class Tiger implements Comparable{
	private int size;
	 
    public Tiger(int s) {
        size = s;    
    }    
    
    public int getSize() {
		return size;
	}
    
	public int compareTo(Object o) {
    	System.out.println("Tiger compareTo()~~~~~~~~~~~");
        return size - ((Tiger) o).getSize();
    }
}



ObjectHashSetTest



import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.TreeSet;


public class ObjectHashSetTest {

	public static void main(String[] args) {
		System.out.println("==========Cat HashSet ==============");
		HashSet<Cat> hs = new HashSet<Cat>();  
		hs.add(new Cat(2));  
		hs.add(new Cat(1));  
		hs.add(new Cat(3));  
		hs.add(new Cat(5));  
		hs.add(new Cat(4)); 
		hs.add(new Cat(4)); 
		System.out.println(hs.size());  //6
		
		System.out.println("========================");
		LinkedHashSet<Cat> lhs= new LinkedHashSet<Cat>();  
		lhs.add(new Cat(2));  
		lhs.add(new Cat(1));  
		lhs.add(new Cat(3));  
		lhs.add(new Cat(5));  
		lhs.add(new Cat(4));  
		lhs.add(new Cat(4));		
		System.out.println(lhs.size());  //6
		
		
		
		System.out.println("==========Dog HashSet ==============");
		HashSet<Dog> hs2 = new HashSet<Dog>();  
		hs2.add(new Dog(2));  
		hs2.add(new Dog(1));  
		hs2.add(new Dog(3));  
		hs2.add(new Dog(5));  
		hs2.add(new Dog(4)); 
		hs2.add(new Dog(4)); 
		System.out.println(hs2.size());  //5
		
		System.out.println("========================");
		LinkedHashSet<Dog> lhs2= new LinkedHashSet<Dog>();  
		lhs2.add(new Dog(2));  
		lhs2.add(new Dog(1));  
		lhs2.add(new Dog(3));  
		lhs2.add(new Dog(5));  
		lhs2.add(new Dog(4));  
		lhs2.add(new Dog(4)); 		
		System.out.println(lhs2.size());  //5
		

		System.out.println("==========Tiger HashSet ==============");	
//HashSet的判定不关心CompareTo方法
		HashSet<Tiger> hs3 = new HashSet<Tiger>();  
		hs3.add(new Tiger(2));  
		hs3.add(new Tiger(1));  
		hs3.add(new Tiger(3));  
		hs3.add(new Tiger(5));  
		hs3.add(new Tiger(4)); 
		hs3.add(new Tiger(4)); 
		System.out.println(hs3.size());  //6
		
		System.out.println("========================");
		LinkedHashSet<Tiger> lhs3= new LinkedHashSet<Tiger>();  
		lhs3.add(new Tiger(2));  
		lhs3.add(new Tiger(1));  
		lhs3.add(new Tiger(3));  
		lhs3.add(new Tiger(5));  
		lhs3.add(new Tiger(4));  
		lhs3.add(new Tiger(4)); 		
		System.out.println(lhs3.size());  //6
	}
}



输出:



5
6
6
============for循环遍历==============
3
6
20
1000
40000
5000000
============迭代器遍历==============
8987700纳秒
============for-each遍历==============
6676000纳秒
PS C:\Users\zhang\Documents\VS Code\Java\JavaCoreTechnique\SetDemo>  cd 'c:\Users\zhang\Documents\VS Code\Java\JavaCoreTechnique\SetDemo'; & 'C:\Users\zhang\.vscode\extensions\vscjava.vscode-java-debug-0.25.1\scripts\launcher.bat' 'C:\Program Files\Java\jdk-12.0.2\bin\java.exe' '-agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=localhost:8842' '-Dfile.encoding=UTF-8' '-cp' 'C:\Users\zhang\Documents\VS Code\Java\JavaCoreTechnique\SetDemo\bin' 'HashSetJudgeRuleTest'
4
PS C:\Users\zhang\Documents\VS Code\Java\JavaCoreTechnique\SetDemo>  cd 'c:\Users\zhang\Documents\VS Code\Java\JavaCoreTechnique\SetDemo'; & 'C:\Users\zhang\.vscode\extensions\vscjava.vscode-java-debug-0.25.1\scripts\launcher.bat' 'C:\Program Files\Java\jdk-12.0.2\bin\java.exe' '-agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=localhost:8863' '-Dfile.encoding=UTF-8' '-cp' 'C:\Users\zhang\Documents\VS Code\Java\JavaCoreTechnique\SetDemo\bin' 'ObjectHashSetTest'
==========Cat HashSet ==============
6
========================
6
==========Dog HashSet ==============
Dog hashCode()~~~~~~~~~~~
Dog hashCode()~~~~~~~~~~~
Dog hashCode()~~~~~~~~~~~
Dog hashCode()~~~~~~~~~~~
Dog hashCode()~~~~~~~~~~~
Dog hashCode()~~~~~~~~~~~
Dog equals()~~~~~~~~~~~
5
========================
Dog hashCode()~~~~~~~~~~~
Dog hashCode()~~~~~~~~~~~
Dog hashCode()~~~~~~~~~~~
Dog hashCode()~~~~~~~~~~~
Dog hashCode()~~~~~~~~~~~
Dog hashCode()~~~~~~~~~~~
Dog equals()~~~~~~~~~~~
5
==========Tiger HashSet ==============
6
========================
6



这三个方法三位一体:

  • equals()是相同的
  • hashCode()是相同的
  • toString()也应该是相同的

TreeSet例程



import java.util.TreeSet;


public class ObjectTreeSetTest {

	public static void main(String[] args) {
		/*
		System.out.println("==========Cat TreeSet ==============");
		TreeSet<Cat> ts = new TreeSet<Cat>();  
		ts.add(new Cat(2));  
		ts.add(new Cat(1));  
		ts.add(new Cat(3));  
		ts.add(new Cat(5));  
		ts.add(new Cat(4)); 
		ts.add(new Cat(4)); 
		System.out.println(ts.size());  //5		
		
		System.out.println("==========Dog TreeSet ==============");
		
		
		TreeSet<Dog> ts2 = new TreeSet<Dog>();  
		ts2.add(new Dog(2));  
		ts2.add(new Dog(1));  
		ts2.add(new Dog(3));  
		ts2.add(new Dog(5));  
		ts2.add(new Dog(4)); 
		ts2.add(new Dog(4)); 
		System.out.println(ts2.size());  //5
		*/
		
		//添加到TreeSet的,需要实现Comparable接口,即实现compareTo方法

		System.out.println("==========Tiger TreeSet ==============");
		
		
		TreeSet<Tiger> ts3 = new TreeSet<Tiger>();  
		ts3.add(new Tiger(2));  
		ts3.add(new Tiger(1));  
		ts3.add(new Tiger(3));  
		ts3.add(new Tiger(5));  
		ts3.add(new Tiger(4)); 
		ts3.add(new Tiger(4)); 
		System.out.println(ts3.size());  //5
	}
}



结果



==========Tiger TreeSet ==============
Tiger compareTo()~~~~~~~~~~~
Tiger compareTo()~~~~~~~~~~~
Tiger compareTo()~~~~~~~~~~~
Tiger compareTo()~~~~~~~~~~~
Tiger compareTo()~~~~~~~~~~~
Tiger compareTo()~~~~~~~~~~~
Tiger compareTo()~~~~~~~~~~~
Tiger compareTo()~~~~~~~~~~~
Tiger compareTo()~~~~~~~~~~~
Tiger compareTo()~~~~~~~~~~~
5