关于Set的一些小总结
Set是Collection接口下的重要的子接口,在Collection的基础上加入不允许元素重复的限制,除此这外Set的行为与Collection很类似。
首先,几个小说明:
Set要保持内部元素的唯一性,他是通过元素的equals()方法来实现的,就是不允许Set中两个元素equals返回true。这里有两个小细节:
1, 如果一个实现了Set接口的对象(下面简称Set对象或Set)中已经含有某元素,再次向Set中add()此元素时,add方法不会抛异常,而只是返回一个false,如果你要确定加入某元素一定要进行判断是否加入成功。
2, Set接口中还有一个叫做addAll的方法,可以接收一个Collection将其中的元素都加入到这个set中,这时如果加入的Collection中所有的元素set中原来都有,就是set中一个元素都不会增加,这时返回false,否则,只要有一个元素被加入到了Set中,就会返回true。
例子程序:
<span style="font-size:14px;">package cn.com.taiji.test;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
public class TestSet {
public static void main(String[] args) {
Set<String> s1 = new HashSet<String>();
System.out.println(s1);
System.out.println(s1.add("a"));// true
System.out.println(s1.add("a"));// false
System.out.println(s1.add("b"));// true
System.out.println(s1); // [b, a]
Set<String> s2 = new HashSet<String>();
System.err.println(s2.add("a"));
System.err.println(s2.add("c"));
System.out.println(s2.addAll(s1));// true
System.out.println(s2.addAll(s1));// false
System.out.println(s2); // [b, c, a]
Set<String> s3 = new TreeSet<String>(s2);// 正常,因为String实现了Comparable接口
System.out.println(s3); // [a, b, c]
// Set<Cat> s4 = new TreeSet<Cat>(s2); // 错误,因为Cat没有实现Comparable接口
for (String str : s3) {
if (str.equals("a")) {
s3.remove(str);
}
}
}
}
class Cat {
@Override
public boolean equals(Object obj) {
return true;
}
}</span>
3, 关于equals方法,只要两个对象的equals方法返回的是true就认为两元素是相等的,不管到底是不是同一个类,所以我们在使用时最好最好加上泛型,防止莫名其妙的问题出现。
4, 与add和addAll方法对应的有remove和removeAll,不再详细说。
5, 还有一点要注意的的,HashSet中是可以将null加进去的,所以使用时要判断是否为null或取之前就将null元素直接删除。TreeSet中不允许出现null元素。
下面说一下最常用的HashSet和TreeSet,主要说一下相同和不同的地方。
HashSets构造方法:
TreeSet构造方法:
1, HashSet底层使用Hash表的数据结构进行存储,元素所存在的顺序是由元素的Hash地址决定的,所以不能保证元素的有序排列(事实上如果元素类没有实现Comparable接口的话,谈元素顺序是没有意义的)。
2, TreeSet底层使用了平衡树,能将元素进行有序,可以通过改变Comparator来改变排序的方法。
3, 空参数的构造方法相同,不说。传入一个Collection的方法相同,但是这里要注意并不是所有的Collection都可以传到TreeSet中的,因为TreeSet要求元素都要实现Comparable接口,所以这个Collection中的元素也要实现Comparable接口才可以传进来。
4, HashSet中有一个有初始容量的参数,如果能确定你所需要的Set要装入多少元素,写上这个参数可以提高一点效率,不用再去增加容量。载入因子loadFactor,就是装入的数据点整个哈希表的比例;
下面是初始容量为4的HashSet加入5个元素后的结果
1, 而TreeSet中可以传入比较器,可以传入实现了SortedSet接口的对象进而初始化TreeSet。
2, 关于HashSet,我们重写它的HashCode方法时要注意,保证如果两个元素Equals,则他们的哈希码应该相同。这个对象的哈希码一定要有一定的稳定性,因为HashSet要通过哈希值去操作元素,如果Set内元素的HashCode变化了,以后就不能正确地取到对应元素了。
Set的遍历问题是个问题,可能我们要习惯使用Iterator了,因为,不能用索引,因为Set中元素无任何顺序,也不要用加强的for循环,这种方法没有办法对集合进行操作。Iterator也不能修改,但是也以删除。
还有是Set与数组类型的转化,Collection中有toArray,以及Collections中有许多操作Set的工具方法。
暂时就想到这些,先记下来。