Java集合总结
先来一张 集合 的"家庭照"
Collection是一个接口,所有其子类(也是接口)需要重写其全部的方法!
特别说明:
Collection 和 Collections 长的太像了,容易混淆,这里就特别说明下:
Collection
Collection 是集合的顶级接口(Iterable是JDK1.5新增),其定义了一些必要方法。如下:
|-- iterator //获取集合迭代器对象
|-- size //获取集合长度
|-- add //添加集合元素
|-- addAll //添加集合元素
|-- remove //删除集合元素
|-- removeAll //删除集合元素
|-- clear //清空集合元素
|-- contains //判断集合中是否包含某个元素
|-- containsAll //判断集合中是否包含某个元素
|-- isEmpty //判断集合是否有元素
|-- equals //判断两个集合是否相等
|-- retainAll //获取两个集合中相同的元素,存到调用者的容器中,相当于:替换调用者原来的元素
|-- hashCode //获取集合哈希码值
|-- toArray // 获取集合迭代器对象
Collections
Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法。
此类不能实例化。就像一个工具类,服务于Java的Collection框架。常用方法说明如下:
|-- sort(List<T> list) //对 List集合进行排序(默认的是升序排列)(不适用与 Set集合)
|-- sort(List<T> list, Comparator<? super T> c) //对 List集合进行排序(可以传递自定义的比较器)(不适用与 Set集合)
|-- shuffle(List<?> list) // 对 List 集合中的元素进行随机排列
|-- binarySearch(List<? extends T> list, T key) //折半查找
|-- reverse(List<?> list) //反转 List 集合
|-- reverseOrder() //逆转对象的自然顺序 或 比较器
集合 Collection 派系介绍
List 派系
- 有序 (存、取的顺序相同-怎么存,怎么取)
- 有索引(可以通过索引精准操作数据)
- 允许存储重复元素
- ArrayList
- 底层数据结构是:一个长度可变的数组(数组本身长度不可变), 初始化的长度是 10(可变原理: 通过对数组的复制进行扩容,扩容增长率: 50%)。
- 线程不安全, 运行速度快
- 查询速度快, 增删速度慢
- LinkedList
- 底层数据结构: 链表结构(采用对象之间的地址记录位置)
- 线程不安全, 运行速度快
- 查询速度慢, 增删速度快
- Vector( Vector 被 ArrayList 取代)
- 底层数据结构是一个长度可变的数组(和ArrayList一样,不同的是扩容增长率: 100%)。
- 线程安全, 运行速度慢
- 查询速度快, 增删速度慢
Set 派系
- 无序 (存、取顺序可能不一样)
- 无索引
- 不允许存储重复元素
-
HashSet(无序)
- 单重链接列表
- 底层数据结构:哈希表(实际上是一个HashMap实例, 根据底层源码可得: 底层是一个HashMap )
- 线程不安全、运行速度快
- LinkedHashSet(有序)
- LinkedHashSet始于JDK1.4,Set始于JDK1.2
- 双重链接列表, 底层基于链表的哈希表实现
- 具有可预知迭代顺序(存、取顺序一致)
- 线程不安全, 运行速度快,存取速度快
- LinkedHashSet(有序)
-
TreeSet(有序且唯一)
- 底层数据结构基于: 红黑树
- 可以对存储的元素进行排序
- 线程不安全, 运行速度快
集合 Map 派系
- 采用了 Key-value键值对映射的方式进行存储。
- key是无序、唯一的,value是无序不唯一的。
-
HashMap(无序)
- 底层数据结构:哈希表
- 线程不安全,运行速度快,存取速度快
- 允许 存储'null'值、'null'键
- LinkedHashMap
- 底层数据结构:哈希表
- 键有迭代顺序(存、取顺序一致)
- 线程不安全,运行速度快
- LinkedHashMap
-
TreeMap(有序)
- 底层结构:红黑树(可以按照对象的自然顺序进行排序)
- 键(对象):必须要有自然顺序,或采用比较器(作为键必须要有自然顺序或者使用了比较器,否则会报错)
- 线程不安全,运行速度快
-
HashTable( 无序,HashTable 被 HashMap 取代)
- 底层数据结构:哈希表
- 键(对象):必须重写方法:hashCode()、equals()
- 不允许存'null'( 键、值 都不允许为'null', 若存'null',编译时期不报错,运行时期会抛出空指针异常 )
- 线程安全,运行速度慢
- Properties(无序)
- 底层数据结构:哈希表
- 不允许重复键
- 存、取顺序不确定(无序)
- 线程安全,运行速度慢
- Properties(无序)
常见的数据结构(数据存储方式)
栈:数据 先进 后出
队列:数据 先进 先出
数组:按照索引进行存储
链表:存储数据,按照地址的记录方式存储(前面记住后面的 或 后面记住前面的 依次类推)
树:存储的数据在容器中像树结构那样,对象可以排序 (红黑树)
哈希表:存储对象依赖对象的哈希值
Map集合的迭代(遍历)
迭代步骤
-
- 使用集合的方法: iterator() 获取迭代器对象(获取的是 Iterator 接口的实现类对象)。
-
- 使用迭代器对象, 调用方法 hasNext()、next() 进行集合的遍历。
迭代的两种方式
- 方式一:KeySet 方式(特点:代码少、原理简单, 开发中常用)
HashMap<String, Integer> map = new HashMap<>();
//获取所有的键'key', 存储到 Set 集合中
Set<String> keys = map.keySet();
Iterator<String> iterator = keys.iterator();
while (iterator.hasNext()) {
String key = iterator.next();
Integer value = map.get(key);
}
- 方式二:entrySet 方式
HashMap<String, String> map = new HashMap<>();
Set<Map.Entry<String, String>> entries = map.entrySet();
Iterator<Map.Entry<String, String>> iterator = entries.iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
String key = entry.getKey();
String value = entry.getValue();
}
迭代说明
- 获取迭代器对象, 迭代器对象内有一个值 lastRet(可以看成指针), 其原始值是 -1,
- hasNext(): 指针判断是否有数据, 有返回true, 没有返回false
- next(): 指针位置向后移动一位, 获取当前位置的数据并返回
- 特别注意:一次 hasNext() 判断 只能有一次 next() 调用, 每调用一次 next() 指针都会向后移动一位!
//错误代码如示:
while (iterator.hasNext()) {
System.out.println(iterator.next()+"..."+map.get(iterator.next()));
}
迭代原理
Collection 集合的每个实现类, 其内部是不同的。故而对于每个集合子类, 它们存储对象的方式是不同的。每个集合子类中定义一个内部类(Itr)去实现 Iterator 接口并重写方法, 各自实现查询、获取的操作。
//以 ArrayList 为列,其内部重写了 Collection 的方法 iterator()
//并返回实现了 Iterator 接口的内部类对象
public Iterator<E> iterator() {
return new Itr();
}
/************************************************************/
//Java Iterator 接口源码中: 4个方法 (能看到的只有4个)
public interface Iterator<E> {
//查找集合中是否还有下一个元素,有则返回true, 没有返回false
boolean hasNext();
//返回集合中的下一个元素
E next();
//遍历过程中,移除集合中的元素
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
Map 和 Collection 的区别( Map:映射键值对 )
- Map 并不继承于 Collection 接口 ( Map 和 Collection 都是顶级接口 )
- Map 一个键对应一个值( 键不能重复, 值可以重复 )
- Map: 所有的子接口或实现类, 存储对象的时候, 每次存储两个对象(键 和 值)(add)
- Collection: 所有的子接口或实现类, 每次只能存储一个对象(值)(put)
- Map 是双列的, Collection 是单列的
Array(数组)和 ArrayList(集合)的区别
数组:Array
- 表示形式:int[] array = new int[3] 或 int[] array =
- 数据:改、查。长度大小固定!在内存中是连续的,速度较快,操作简单
集合:ArrayList
- 表示形式: ArrayList
list = new ArrayList(); - 数据:可 增、删、改、查。长度大小可动态增长