Set:无顺序,不包含重复的元素
HashSet:为快速查找设计的Set。存入HashSet的对象必须定义hashCode()。
TreeSet: 保存次序的Set, 底层为树结构。使用它可以从Set中提取有序的序列。
LinkedHashSet:具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。
HashSet:
importjava.util.HashSet;importjava.util.Iterator;public classMain {public static voidmain(String[] args) {
HashSet set= newHashSet();//分别向books集合中添加两个A对象,两个B对象,两个C对象
set.add(newA());
set.add(newA());
set.add(newB());
set.add(newB());
set.add(newC());
set.add(newC());
System.out.println(set);
System.out.println(set.size());for(Iterator iter =set.iterator(); iter.hasNext();){
Object value=iter.next();
System.out.println(value);
}
}
}//类A的equals方法总是返回true,但没有重写其hashCode()方法。不能保证当前对象是HashSet中的唯一对象
classA
{public booleanequals(Object obj)
{return true;
}
}//类B的hashCode()方法总是返回1,但没有重写其equals()方法。不能保证当前对象是HashSet中的唯一对象
classB
{public inthashCode()
{return 1;
}
}//类C的hashCode()方法总是返回2,且有重写其equals()方法
classC
{public inthashCode()
{return 2;
}public booleanequals(Object obj)
{return true;
}
}
Result:
[com.qhong.B@1, com.qhong.B@1, com.qhong.C@2, com.qhong.A@677327b6, com.qhong.A@1540e19d]5com.qhong.B@1com.qhong.B@1com.qhong.C@2com.qhong.A@677327b6
com.qhong.A@1540e19d
View Code
B类的hashcode值一样,但是没有定义equals,所以存储了两个对象,但是对象因为hashcode一样,存储位置也一样,两个对象按链表方式存储。
C类中hashcode值一样,equals也一样,所以只能存储一个值。
A类中没有定义hashcode,所以存储位置不一样,这里还没有进行equals对比,一样存储两个对象。
LinkedHashSet
importjava.util.Iterator;importjava.util.LinkedHashSet;public classMain {public static voidmain(String[] args) {
LinkedHashSet books= newLinkedHashSet();
books.add("Java1");
books.add("Java2");
System.out.println(books);//删除 Java
books.remove("Java1");//重新添加 Java
books.add("Java1");
System.out.println(books);for(Iterator iter =books.iterator(); iter.hasNext();){
Object value=iter.next();
System.out.println(value);
}
}
}
Result:
[Java1, Java2]
[Java2, Java1]
Java2
Java1
View Code
元素的顺序总是与添加顺序一致,LinkedHashSetTest是HashSet的子类,因此它不允许集合元素重复.
TreeSet:
importjava.util.TreeSet;public classMain {public static voidmain(String[] args) {
TreeSet nums= newTreeSet();//向TreeSet中添加四个Integer对象
nums.add(5);
nums.add(2);
nums.add(10);
nums.add(-9);//输出集合元素,看到集合元素已经处于排序状态
System.out.println(nums);//输出集合里的第一个元素
System.out.println(nums.first());//输出集合里的最后一个元素
System.out.println(nums.last());//返回小于4的子集,不包含4
System.out.println(nums.headSet(4));//返回大于5的子集,如果Set中包含5,子集中还包含5
System.out.println(nums.tailSet(5));//返回大于等于-3,小于4的子集。
System.out.println(nums.subSet(-3 , 4));
}
}
Result:
[-9, 2, 5, 10]-9
10[-9, 2]
[5, 10]
[2]
View Code
与HashSet集合采用hash算法来决定元素的存储位置不同,TreeSet采用红黑树的数据结构来存储集合元素。
TreeSet支持两种排序方式: 自然排序、定制排序
TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序排序,即自然排序。
通过ComparaTor接口可以实现定制排序。
importjava.util.Comparator;importjava.util.Iterator;importjava.util.TreeSet;public classMain {public static voidmain(String[] args) {
TreeSet ts= new TreeSet(newComparator()
{//根据M对象的age属性来决定大小
public intcompare(Object o1, Object o2)
{
M m1=(M)o1;
M m2=(M)o2;return m1.age > m2.age ? -1 : m1.age < m2.age ? 1 : 0;
}
});
ts.add(new M(5));
ts.add(new M(-3));
ts.add(new M(9));
System.out.println(ts);for(Iterator iter =ts.iterator(); iter.hasNext();){
Object value=iter.next();
System.out.println(value);
}
}
}classM
{intage;public M(intage)
{this.age =age;
}publicString toString()
{return "M[age:" + age + "]";
}
}
Result:
[M[age:9], M[age:5], M[age:-3]]
M[age:9]
M[age:5]
M[age:-3]
View Code
EnumSet:
importjava.util.EnumSet;public classMain {public static voidmain(String[] args) {//创建一个EnumSet集合,集合元素就是Season枚举类的全部枚举值
EnumSet es1 = EnumSet.allOf(Season.class);//输出[SPRING,SUMMER,FALL,WINTER]
System.out.println(es1);//创建一个EnumSet空集合,指定其集合元素是Season类的枚举值。
EnumSet es2 = EnumSet.noneOf(Season.class);//输出[]
System.out.println(es2);//手动添加两个元素
es2.add(Season.WINTER);
es2.add(Season.SPRING);//输出[SPRING,WINTER]
System.out.println(es2);//以指定枚举值创建EnumSet集合
EnumSet es3 =EnumSet.of(Season.SUMMER , Season.WINTER);//输出[SUMMER,WINTER]
System.out.println(es3);
EnumSet es4=EnumSet.range(Season.SUMMER , Season.WINTER);//输出[SUMMER,FALL,WINTER]
System.out.println(es4);//新创建的EnumSet集合的元素和es4集合的元素有相同类型,//es5的集合元素 + es4集合元素 = Season枚举类的全部枚举值
EnumSet es5 =EnumSet.complementOf(es4);//输出[SPRING]
System.out.println(es5);
}
}enumSeason
{
SPRING,SUMMER,FALL,WINTER
}
Result:
[SPRING, SUMMER, FALL, WINTER]
[]
[SPRING, WINTER]
[SUMMER, WINTER]
[SUMMER, FALL, WINTER]
[SPRING]
View Code
Set集合类应用场景:
1) HashSet的性能总是比TreeSet好(特别是最常用的添加、查询元素等操作),因为TreeSet需要额外的红黑树算法来维护集合元素的次序。只有当需要一个保持排序的Set时,才应该使用TreeSet,否则都应该使用HashSet2) 对于普通的插入、删除操作,LinkedHashSet比HashSet要略慢一点,这是由维护链表所带来的开销造成的。不过,因为有了链表的存在,遍历LinkedHashSet会更快3) EnumSet是所有Set实现类中性能最好的,但它只能保存同一个枚举类的枚举值作为集合元素4) HashSet、TreeSet、EnumSet都是"线程不安全"的,通常可以通过Collections工具类的synchronizedSortedSet方法来"包装"该Set集合。
SortedSet s= Collections.synchronizedSortedSet(new TreeSet(...));