文章目录
一、简介
集合是 java 中提供的一种容器,可以用来存储多个对象数据。
既然有数组作为数据容器,Java为什么还提供集合容器?它们有啥区别呢?
- 数组的长度是固定的,不利于数据的增删。集合的长度是可变的。
- 数组中提供的属性和方法较少,不便于进行常用的增删改查操作,集合提供了更丰富的API。
- 数组存储数据的特点单一,即有序的,可重复的。集合有很多种类型,分别有不同的存储特点。
集合主要分为两大系列:Collection 和 Map,Collection 表示一组对象,Map表示一组映射关系或键值对。
二、Collection
Collection 表示一组对象。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。
所以JDK 不提供此接口的任何直接实现:它提供更具体的子接口(如Set
和List
、Queue
)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。
Collection 常用方法
方法名称 | 方法描述 |
---|---|
add(E obj) | 添加元素对象到当前集合中 |
addAll(Collection<? extends E> other) | 添加other集合中的所有元素对象到当前集合中 |
boolean remove(Object obj) | 从当前集合中删除第一个找到的与obj对象equals返回true的元素。 |
boolean removeAll(Collection<?> coll) | 从当前集合中删除所有与coll集合中相同的元素。 |
void clear() | 清空集合 |
boolean isEmpty() | 判断当前集合是否为空集合 |
boolean contains(Object obj) | 判断当前集合中是否存在一个与obj对象equals返回true的元素。 |
boolean containsAll(Collection<?> c) | 判断c集合中的元素是否在当前集合中都存在。即c集合是否是当前集合的“子集”。 |
int size() | 获取当前集合中实际存储的元素个数 |
boolean retainAll(Collection<?> coll) | 当前集合仅保留与c集合中的元素相同的元素,即当前集合中仅保留两个集合的交集 |
Object[] toArray() | 返回包含当前集合中所有元素的数组 |
Iterator 迭代器
在程序开发中,经常需要遍历集合中的所有元素。针对这种需求,JDK专门提供了一个接口
java.util.Iterator
。Iterator
接口也是Java集合中的一员,但它与Collection
、Map
接口有所不同,Collection
接口与Map
接口主要用于存储元素,而Iterator
主要用于迭代访问(即遍历)Collection
中的元素,因此Iterator
对象也被称为迭代器。
常用方法:
方法名称 | 方法描述 |
---|---|
public E next() | 返回迭代的下一个元素 |
public boolean hasNext() | 如果仍有元素可以迭代,则返回 true |
public void remove() | 通过迭代器删除元素 |
增强 for(foreach循环)
增强for循环(也称 foreach循环 )是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。
通常只进行遍历元素,不要在遍历的过程中进行其他操作,否者会触发快速失败机制
。
Iterable 接口
实现这个接口允许对象成为 “foreach” 语句的目标。
Java 5时Collection接口继承了Iterable接口,因此Collection系列的集合就可以直接使用foreach循环遍历。
Iterable接口包含抽象方法public Iterator iterator(): 获取对应的迭代器。
foreach本质上就是使用Iterator迭代器进行遍历的
快速失败机制
当使用foreach或Iterator迭代器遍历集合时,同时调用迭代器自身以外的方法修改了集合的结构,例如调用集合的add和remove方法时,就会
ConcurrentModificationException
。
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class TestForeach {
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
list.add("hello");
list.add("java");
list.add("world");
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
list.remove(iterator.next());
}
}
}
这样设计是因为,迭代器代表集合中某个元素的位置,内部会存储某些能够代表该位置的信息。当集合发生改变时,该信息的含义可能会发生变化,这时操作迭代器就可能会造成不可预料的事情。因此,果断抛异常阻止,是最好的方法。这就是Iterator迭代器的快速失败(fail-fast)机制。
三、List
java.util.List
接口继承自Collection
接口,是单列集合的一个重要分支。除了从Collection集合继承的方法外,List 集合里添加了一些根据索引来操作集合元素的方法。
List 集合类中元素 有序、且可重复
List 集合的方法
List 集合特有的方法都是跟索引相关
方法名称 | 方法描述 |
---|---|
void add(int index, E ele) | 添加元素 |
boolean addAll(int index, Collection<? extends E> eles) | 添加元素 |
E get(int index) | 获取元素 |
List subList(int fromIndex, int toIndex) | 获取元素 |
int indexOf(Object obj) | 获取元素索引 |
int lastIndexOf(Object obj) | 获取元素索引 |
E remove(int index) | 删除和替换元素 |
E set(int index, E ele) | 删除和替换元素 |
一、 ArrayList
ArrayList是 List 接口的典型实现类,底层使用长度可变的数组实现,常用方法都来自Collection和List接口。
ArrayList因为底层使用了数组存储数据,所以具有 查询快,增、删慢 的特点。
二、LinkedList
LinkedList 是List接口的另一个常用实现类。
LinkedList 底层存储数据使用链表结构(双向链表),特点:增删快,查询慢。
LinkedList 也实现了Deque接口(双端队列),此接口提供了实现队列和栈结构的方法。
1. 常用方法(首、尾元素的操作,效率高):
- void addFirst(Object obj )
- void addLast(Object obj )
- Object getFirst()
- Object getLast()
- Object removeFirst()
- Object removeLast ()
三、ListIterator
List 集合额外提供了一个 listIterator() 方法,该方法返回一个 ListIterator 对象, ListIterator 接口继承了 Iterator 接口,提供了专门操作 List 的方法:
- void add():通过迭代器添加元素到对应集合
- void set(Object obj):通过迭代器替换正迭代的元素
- void remove():通过迭代器删除刚迭代的元素
- boolean hasPrevious():如果以逆向遍历列表,往前是否还有元素。
- Object previous():返回列表中的前一个元素。
- int previousIndex():返回列表中的前一个元素的索引
- boolean hasNext()
- Object next()
- int nextIndex()
四、Set 集合
Set接口是Collection的子接口,Set 集合不允许包含相同的元素,即元素唯一。
Set的常用实现类有:HashSet、TreeSet、LinkedHashSet。
一、HashSet
HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。
java.util.HashSet
底层的实现其实是一个java.util.HashMap
支持,然后HashMap的底层物理实现是一个Hash表。
HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。
1. HashSet 集合判断两个元素相等的标准:
1.两个对象通过 hashCode() 方法比较相等
2.并且两个对象的 equals() 方法返回值也相等。
因此,存储到HashSet的元素要重写hashCode和equals方法。
2. 为什么重写hashCode方法
提高哈希性能。
如何重写hashCode方法, 提高哈希性能
内容相同的元素哈希值一定相同
内容不同的元素哈希值尽量不同
哈希值相同不一定是相同的元素
可以使用IDEA模板重写hashCode和equals方法
二、LinkedHashSet
LinkedHashSet是HashSet的子类,它在HashSet的基础上,在结点中增加两个属性before和after维护了结点的前后添加顺序。java.util.LinkedHashSet
,它是链表和哈希表组合的一个数据存储结构。LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。
三、 TreeSet
元素唯一,无序(存取顺序), 但是实现了排序(大小排序)
底层结构:里面维护了一个TreeMap,都是基于红黑树实现的。
红黑树是一种相对平衡的二叉树,查询效率高于链表。(平衡二叉树追求绝对平衡,左右子树差值不能超过1)
实现了元素的排序,即TreeSet会对元素进行大小比较
要求:
元素类型必须实现Comparable接口
创建集合是通过构造器传入一个外部比较器Comparator
二叉树的遍历方式有:
- 前序遍历:中-左-右
- 中序遍历:左-中-右
- 后序遍历:左-右-中
五、Map
现实生活中,我们常会看到这样的一种集合:IP地址与主机名,身份证号与个人等,这种一一对应的关系,就叫做映射。Java提供了专门的集合类用来存放这种对象关系的对象,即
java.util.Map<K,V>
接口。
Collection
中的集合称为单列集合,Map
中的集合称为双列集合。
一、Map 常用方法
方法名称 | 方法描述 |
---|---|
V put(K key,V value) | 添加操作 |
void putAll(Map<? extends K,? extends V> m) | 添加操作 |
void clear() | 删除 |
V remove(Object key) | 删除 |
V get(Object key) | 元素查询的操作 |
boolean containsKey(Object key) | 元素查询的操作 |
boolean containsValue(Object value) | 元素查询的操作 |
boolean isEmpty() | 判断元素是否为空 |
Set keySet() | 返回 key 的集合 |
Collection values() | 返回 value 的集合 |
Set<Map.Entry<K,V>> entrySet() | 返回 key, 和value, 封装到 entry 中 |
int size() | 返回集合的长度 |
二、Map 集合的遍历
Map的遍历,不能支持foreach,因为Map接口没有继承java.lang.Iterable接口,也没有实现Iterator iterator()方法。只能用如下方式遍历:
(1)分开遍历:
- 单独遍历所有key
- 单独遍历所有value
(2)成对遍历:
- 遍历的是映射关系Map.Entry类型的对象,Map.Entry是Map接口的内部接口。每一种Map内部有自己的Map.Entry的实现类。在Map中存储数据,实际上是将Key---->value的数据存储在Map.Entry接口的实例中.
三、Map实现类
Map接口的常用实现类
其中HashMap是 Map 接口使用频率最高的实现类。HashMap
Hashtable
TreeMap
LinkedHashMap
Properties
HashMap
HashMap 使用 哈希表保存数据
判断两个 key 相等的标准是:两个 key 的hashCode 值相等,并且 equals() 方法也返回 true。因此,为了成功地在哈希表中存储和获取对象,用作键的对象必须实现 hashCode 方法和 equals 方法。
- HashMap是线程不安全的,并允许使用 null 值和 null 键。、
HashMap构造方法:
- HashMap();
- HashMap(int initialCapacity);//指定初始化容量
Hahtable
和HashMap基本上一样,不常用
- Hashtable是线程安全的,任何非 null 对象都可以用作键或值。
LinkedHashMap
LinkedHashMap 是 HashMap 的子类。
特点: 元素唯一,有序
底层结构:哈希表基础上又维护了一个链表,用于保证元素的迭代顺序。
效率:略低于HashMap
TreeMap
特点:元素唯一,无序, 但实现了排序(大小排序)
底层机构:红黑树,一种相对平衡的二叉树
效率:查询效率高于链表。
该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。
Properties
Properties 类是 Hashtable 的子类。
特点:key和value都是字符串
特有方法
setProperty(String key,String value)
getProperty(String key)
六、总结
Collection:集合根接口,存储一组对象。
- List:Collection的子接口。数据可重复,有序的,通过索引访问元素。
- ArrayList:
存储结构:数组存储
特点:查询效率高, 增删慢 - LinkedList:
存储结构:双向链表
特点:查询效率低, 但是插入和删除效率高 - Vector:
等同于 Arraylist实现,线程安全的,效率较低
- ArrayList:
- Set:Collection的子接口,数据不可重复,通常无序,不能通过索引访问。
- HashSet:
存储结构:底层是HashMap
特点: 综合效率较高。 - LinkedHashSet: 底层是 LinkedHashMap
存储结构: 哈希表基础维护了一个链表, 用来保证数据有序
特点: 效率没有HashSet高, 有序数据 - TreeSet:
存储机构:使用红黑树存储
特点:因为红黑树的原因, 数据是自动排序好的。
- HashSet:
Map: 双列集合,存储的是Key, value
- HashMap:
存储结构:JDK1.7 数组 + 链表 JDK1.8 数组 + 链表 + 红黑树
特点:线程不安全,允许 key, value为 null - Hashtable:
存储结构: 等同于 HashMap
特点: 线程安全, key, value都不能为 null - LinkedHashMap:
存储结构:HashMap之上维护了链表
特点: 按照插入顺序存储 - TreeMap:
可对键排序 - Properties
存储结构
特点: 只能存储Stirng 类型的 数据。
Collections工具类
Collections 是一个操作 Set、List 和 Map 等集合的工具类。Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法:
方法名称 | 方法描述 |
---|---|
public static boolean addAll(Collection<? super T> c,T… elements) | 将所有指定元素添加到指定 collection 中。 |
public static int binarySearch(List<? extends Comparable<? super T>> list,T key) | 在List集合中查找某个元素的下标,但是List的元素必须是T或T的子类对象,而且必须是可比较大小的,即支持自然排序的。而且集合也事先必须是有序的,否则结果不确定。 |
public static int binarySearch(List<? extends T> list,T key,Comparator<? super T> c) | 在List集合中查找某个元素的下标,但是List的元素必须是T或T的子类对象,而且集合也事先必须是按照c比较器规则进行排序过的,否则结果不确定。 |
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) | 在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,而且支持自然排序 |
public static T max(Collection<? extends T> coll,Comparator<? super T> comp) | 在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,按照比较器comp找出最大者 |
public static void reverse(List<?> list) | 反转指定列表List中元素的顺序。 |
public static void shuffle(List<?> list) | List 集合元素进行随机排序,类似洗牌 |
public static <T extends Comparable<? super T>> void sort(List list) | 根据元素的自然顺序对指定 List 集合元素按升序排序 |
public static void sort(List list,Comparator<? super T> c) | 根据指定的 Comparator 产生的顺序对 List 集合元素进行排序 |
public static void swap(List<?> list,int i,int j) | 将指定 list 集合中的 i 处元素和 j 处元素进行交换 |
public static int frequency(Collection<?> c,Object o) | 返回指定集合中指定元素的出现次数 |
public static void copy(List<? super T> dest,List<? extends T> | src)将src中的内容复制到dest中 |
public static boolean replaceAll(List list,T oldVal,T newVal) | 使用新值替换 List 对象的所有旧值 |
- Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题
- Collections类中提供了多个unmodifiableXxx()方法,该方法返回指定 Xxx的不可修改的视图。