Set,即集合,与数学上的定义一样,集合具有三个特点:
- 无序性:一个集合中,每个元素的地位都是相同的,元素之间是无序的。
- 互异性:一个集合中,任何两个元素都认为是不相同的,即每个元素只能出现一次。
- 确定性:给定一个集合,任给一个元素,该元素或者属于或者不属于该集合,二者必居其一,不允许有模棱两可的情况出现。
但是Java中的集合并不是严格意义上的集合,其中的TreeSet集合类并不满足,因为它是有序的,除了无序性这一点,Java中的集合都严格满足其它两点。
在Java中将集合类的起源定义为Set接口,并由该接口扩展出其他具体的实现,它们之间的关系如下:
SortedSet接口继承自Set接口,在其内部定义了排序的行为交由TreeSet实现排序的集合。在AbstractSet抽象类中,与AbstractList类一样,为其子类提供对其自身的操作,即集合类操作,只是集合的内部操作,并没有实现集合间的操作。
HashSet
HashSet类是满足集合属性的三个属性的,插入到其内部的元素是有其hashcode值决定的,其内部的具体实现是由HashMap完成的,平时我们创建一个新的HashSet类,实际上是创建了一个HashMap来完成我们所需的操作,HashSet类的几个构造方法如下:
private transient HashMap<E,Object> map;
public HashSet() {
map = new HashMap<>();
}
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
可见里面都创建了HashMap对象,也就是说,HashSet是利用HashMap的不可重复性来完成集合的互斥性的,示例代码:
String s1=new String("1");
String s2=new String("1");
String s3=new String("1");
Set<String> set=new HashSet<>();
set.add(s1);
set.add(s2);
set.add(s3);
System.out.println(set.add(s1));//false
Iterator iterable=set.iterator();
while (iterable.hasNext()){
System.out.println(iterable.next());//输出:1
}
System.out.println(s1.hashCode()==s2.hashCode());//true
HashMap是根据对象的hashcode值来判断是否是同一个对象的,因为s1、s2、s3的值相同,所以它们的hashcode值也相同,在集合中加入s1与s2时加不进去。下面列出常用的方法:
//获取迭代器
public Iterator<E> iterator() {
return map.keySet().iterator();
}
//获取元素的多少
public int size() {
return map.size();
}
//判断是否为空
public boolean isEmpty() {
return map.isEmpty();
}
//判断是否包含
public boolean contains(Object o) {
return map.containsKey(o);
}
//增加一个元素
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
//移除一个元素
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
//清除所有的元素
public void clear() {
map.clear();
}
TreeSet
TreeSet类是有序的集合类,它实现了SortedSet接口,但与HashSet类相同的是,它也是在内部委托给另外一个类来完成其功能的,这个类是TreeMap类,TreeMap类在其内部实现了红黑树,因此可以实现较快的排序:
public TreeSet() {
this(new TreeMap<E,Object>());
}
还可以直接返回第一个元素以及最后一个元素:
public E first() {
return m.firstKey();
}
public E last() {
return m.lastKey();
}
加入到TreeMap中的元素必须实现Comparable与Comparator接口,用来进行比较,其示例代码如下:
String s1=new String("1");
String s2=new String("3");
String s3=new String("2");
Set<String> set=new TreeSet<>();
set.add(s1);
set.add(s2);
set.add(s3);
Iterator iterable=set.iterator();
while (iterable.hasNext()) {
System.out.println(iterable.next());
}
//输出为:1 2 3
LinkedHashSet
LinkedHashSet继承自HashSet,它不同于HashSet里面的元素是无序的,它是按照元素的插入顺序来保存元素的,也就是说它是线性的,其内部是调用类父类的构造方法:
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
采用了LinkedHashMap来实现其功能,LinkedHashMap是线性的HashMap,所以LinkedHashSet即为线性的。示例代码:
String s1=new String("1");
String s2=new String("32");
String s3=new String("243242");
Set<String> set=new HashSet<>();
set.add(s1);
set.add(s2);
set.add(s3);
Iterator iterable=set.iterator();
while (iterable.hasNext()) {
System.out.println(iterable.next());
}
//输出:1 243242 32
Set<String> set2=new LinkedHashSet<>();
set2.add(s1);
set2.add(s2);
set2.add(s3);
Iterator iterable2=set2.iterator();
while (iterable2.hasNext()) {
System.out.println(iterable2.next());
}
//输出:1 32 243242
总的来说,三者其实是Map类的一个封装而已。