新闻资讯
Java集合框架总览
集合框架总览
工欲善其事必先利其器,让我们先来过一遍整个集合框架的组成部分:
- 集合框架提供了两个遍历接口:Iterator和ListIterator,其中后者是前者的优化版,支持在任意一个位置进行前后双向遍历。注意图中的Collection应当继承的是Iterable而不是Iterator,后面会解释Iterable和Iterator的区别
- 整个集合框架分为两个门派(类型):Collection和Map,前者是一个容器,存储一系列的对象;后者是键值对<key, value>,存储一系列的键值对
- 在集合框架体系下,衍生出四种具体的集合类型:Map、Set、List、Queue
- Map存储<key,value>键值对,查找元素时通过key查找value
- Set内部存储一系列不可重复的对象,且是一个无序集合,对象排列顺序不一
- List内部存储一系列可重复的对象,是一个有序集合,对象按插入顺序排列
- Queue是一个队列容器,其特性与List相同,但只能从队头和队尾操作元素
- JDK 为集合的各种操作提供了两个工具类Collections和Arrays,之后会讲解工具类的常用方法
- 四种抽象集合类型内部也会衍生出许多具有不同特性的集合类,不同场景下择优使用,没有最佳的集合
上面了解了整个集合框架体系的组成部分,接下来的章节会严格按照上面罗列的顺序进行讲解,每一步都会有承上启下的作用
学习Set前,最好最好要先学习Map,因为Set的操作本质上是对Map的操作,往下看准没错
Iterator Iterable ListIterator
在第一次看这两个接口,真以为是一模一样的,没发现里面有啥不同,存在即合理,它们两个还是有本质上的区别的。
首先来看Iterator接口:
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
提供的API接口含义如下:
- hasNext():判断集合中是否存在下一个对象
- next():返回集合中的下一个对象,并将访问指针移动一位
- remove():删除集合中调用next()方法返回的对象
在早期,遍历集合的方式只有一种,通过Iterator迭代器操作
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Iterator iter = list.iterator(); while (iter.hasNext()) {
Integer next = iter.next();
System.out.println(next);
if (next == 2) { iter.remove(); }
}
再来看Iterable接口:
public interface Iterable<T> {
Iterator<T> iterator();
// JDK 1.8 default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
}
可以看到Iterable接口里面提供了Iterator接口,所以实现了Iterable接口的集合依旧可以使用迭代器遍历和操作集合中的对象;
而在 JDK 1.8中,Iterable提供了一个新的方法forEach(),它允许使用增强 for 循环遍历对象。
List<Integer> list = new ArrayList<>(); for (Integer num : list) {
System.out.println(num);
}
我们通过命令:javap -c反编译上面的这段代码后,发现它只是 Java 中的一个语法糖,本质上还是调用Iterator去遍历。
翻译成代码,就和一开始的Iterator迭代器遍历方式基本相同了。
Iterator iter = list.iterator(); while (iter.hasNext()) {
Integer num = iter.next();
System.out.println(num);
}
还有更深层次的探讨:为什么要设计两个接口Iterable和Iterator,而不是保留其中一个就可以了。
简单讲解:Iterator的保留可以让子类去实现自己的迭代器,而Iterable接口更加关注于for-each的增强语法。具体可参考:Java中的Iterable与Iterator详解
关于Iterator和Iterable的讲解告一段落,下面来总结一下它们的重点:
- Iterator是提供集合操作内部对象的一个迭代器,它可以遍历、移除对象,且只能够单向移动
- Iterable是对Iterator的封装,在JDK 1.8时,实现了Iterable接口的集合可以使用增强 for 循环遍历集合对象,我们通过反编译后发现底层还是使用Iterator迭代器进行遍历
等等,这一章还没完,还有一个ListIterator。它继承 Iterator 接口,在遍历List集合时可以从任意索引下标开始遍历,而且支持双向遍历。
ListIterator 存在于 List 集合之中,通过调用方法可以返回起始下标为 index的迭代器
List<Integer> list = new ArrayList<>(); // 返回下标为0的迭代器 ListIterator<Integer> listIter1 = list.listIterator(); // 返回下标为5的迭代器 ListIterator<Integer> listIter2 = list.listIterator(5);
ListIterator 中有几个重要方法,大多数方法与 Iterator 中定义的含义相同,但是比 Iterator 强大的地方是可以在任意一个下标位置返回该迭代器,且可以实现双向遍历。
public interface ListIterator<E> extends Iterator<E> {
boolean hasNext();
E next();
boolean hasPrevious();
E previous();
int nextIndex();
int previousIndex();
void remove();
// 替换当前下标的元素,即访问过的最后一个元素 void set(E e);
void add(E e);
}
Map 和 Collection 接口
Map 接口和 Collection 接口是集合框架体系的两大门派,Collection 是存储元素本身,而 Map 是存储<key, value>键值对,在 Collection 门派下有一小部分弟子去偷师,利用 Map 门派下的弟子来修炼自己。
是不是听的一头雾水哈哈哈,举个例子你就懂了:HashSet底层利用了HashMap,TreeSet底层用了TreeMap,LinkedHashSet底层用了LinkedHashMap。
下面我会详细讲到各个具体集合类哦,所以在这里,我们先从整体上了解这两个门派的特点和区别。
Map接口定义了存储的数据结构是<key, value>形式,根据 key 映射到 value,一个 key 对应一个 value ,所以key不可重复,而value可重复。
在Map接口下会将存储的方式细分为不同的种类:
- SortedMap接口:该类映射可以对<key, value>按照自己的规则进行排序,具体实现有 TreeMap
- AbsractMap:它为子类提供好一些通用的API实现,所有的具体Map如HashMap都会继承它
而Collection接口提供了所有集合的通用方法(注意这里不包括Map):
- 添加方法:add(E e) / addAll(Collection<? extends E> var1)
- 删除方法:remove(Object var1) / removeAll(Collection<?> var1)
- 查找方法:contains(Object var1) / containsAll(Collection<?> var1);
- 查询集合自身信息:size() / isEmpty()
- ···
在Collection接口下,同样会将集合细分为不同的种类:
- Set接口:一个不允许存储重复元素的无序集合,具体实现有HashSet / TreeSet···
- List接口:一个可存储重复元素的有序集合,具体实现有ArrayList / LinkedList···
- Queue接口:一个可存储重复元素的队列,具体实现有PriorityQueue / ArrayDeque···
本内容属于网络转载,文中涉及图片等内容如有侵权,请联系编辑删除
回复列表