之前单列集合只说过了List系列的集合,接下来再说一下Set集合系列,Set集合是无序集合(存取顺序不一致),不允许添加相同元素,Set的实现依赖于Map集合,可以将Set集合看作Map集合键的集合,Map中是不可能包含两个键相同的键值对,所以Set集合不允许相同元素也是为此, Set集合的基本实现类有HashSet、TreeSet、LinkedHashSet等,接下来详细介绍。
HashSet,其实现依赖于HashMap,操作HashSet中的功能方法到最后都是调用的HashMap中的方法,各个功能方法比较容易理解,其源码如下:
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable
{//底层维护一个HashMap,用于存储数据private transient HashMap<E,Object> map;// 虚拟值,以与备份映射中的对象关联private static final Object PRESENT = new Object();//-----------------------构造方法-----------------------////构造HashSet就相当于实例化HashMappublic HashSet() {map = new HashMap<>();}public HashSet(int initialCapacity, float loadFactor) {map = new HashMap<>(initialCapacity, loadFactor);}public HashSet(int initialCapacity) {map = new HashMap<>(initialCapacity);}//保证有序HashSet(int initialCapacity, float loadFactor, boolean dummy) {map = new LinkedHashMap<>(initialCapacity, loadFactor);}//-----------------------功能方法-----------------------////迭代器public Iterator<E> iterator() {return map.keySet().iterator();}//添加方法,其实是给map添加一个键值对,键是添加的元素,值是一个虚拟值,用于组合构建键值对public boolean add(E e) {return map.put(e, PRESENT)==null;}//删除方法,调用的是map中根据key删除键值对的方法public boolean remove(Object o) {return map.remove(o)==PRESENT;}
}
TreeSet集合和LinkedHashSet分别依赖于TreeMap集合和LinkedHashMap集合,Map集合中对双列集合的功能方法,在set集合中对单列集合均可使用。
为了方便操作集合,java提供了一个工具类Collections,类中定义多个静态方法用来直接操作集合可以实现集合的排序、查找、复制、替换、截取等。
最后说一下遍历集合的一些方式,代码如下:
public static void main(String[] args) {List<String> list = new ArrayList<String>();list.add("aaa");list.add("bbb");list.add("ccc");//方式一:遍历集合,然后根据下标获取到每一个位置上的元素,以完成遍历for (int i = 0; i < list.size(); i++) {System.out.println("方式一:"+list.get(i));}//方式二:使用foreach,俗称增强for循环for (String string : list) {System.out.println("方式二:"+string);}//方式三:使用迭代器//实现原理如下边迭代器实现代码Iterator<String> iterator = list.iterator();while (iterator.hasNext()) {//list.add(2, "555");//报错System.out.println("方式三:"+iterator.next());}System.out.println("---------------------------------------------------");Map<String, Object> map = new HashMap<String, Object>();map.put("111", "aaa");map.put("222", "bbb");map.put("333", "ccc");//方式一:通过map内部方法将map中的元素封装到一个Set中,Set中元素的类型确定: Set<Entry<String, Object>>//然后使用Entry类中的方法+set集合遍历来遍历map集合Set<Entry<String, Object>> entrySet = map.entrySet();for (Entry<String, Object> entry : entrySet) {System.out.println("方式一:"+entry.getValue());}//方式二:获取map集合中key的集合,然后根据key获取对应value值Set<String> keySet = map.keySet();for (String key : keySet) {System.out.println("方式二:"+map.get(key));}}-----------------------------迭代器实现代码-----------------------------------
//单列集合都实现了Iterable接口,所以需要实现迭代方法iterator
public interface Iterable<T> { Iterator<T> iterator();
}//使用ArrayList中的迭代器实现为例
public Iterator<E> iterator() {return new Itr();}//迭代器的具体实现
private class Itr implements Iterator<E> {int cursor; // 记录下一个要返回元素的索引 int lastRet = -1; int expectedModCount = modCount;// 修改次数,用来记录修改的次数是否发生了变化//判断是否还有下一个元素public boolean hasNext() {return cursor != size;}//检查集合列表是否被修改,在使用迭代器遍历集合时不允许使用集合方法修改集合内容,否则报错final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}//获取到下一个返回的元素public E next() {checkForComodification();int i = cursor;if (i >= size)throw new NoSuchElementException();//获取到ArrayList集合底层维护的那个存储数据的数组,也就是获取到数组的一个副本//这也是为什么使用迭代器遍历时不能修改集合的原因,操作的是副本Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length)throw new ConcurrentModificationException();cursor = i + 1;return (E) elementData[lastRet = i];}//迭代器中提供了一个remove方法,可用于迭代时删除元素public void remove() {if (lastRet < 0)throw new IllegalStateException();checkForComodification();try {ArrayList.this.remove(lastRet);cursor = lastRet;lastRet = -1;expectedModCount = modCount;} catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException();}}
}
集合的基本使用到这里也就介绍完了。