Collection集合
- 集合:集合是java中提供的一种容器,可以用来存储多个数据。
集合与数组的区别:
-
数组的长度是固定的(数组一旦定义了,就不能再修改数组的长度)。
集合的长度是可变的(可以不断往集合添加元素)。
-
数组中存储的是同一类型的元素,可以存储任意类型数据。
集合存储的都是引用数据类型。如果想存储基本类型数据需要存储对应的包装类型。(String Integer…)
Collection/ List / Set都是接口,不能直接创建对象
Collection接口
- 在集层次结构根接口。一个集合代表一组对象,被称为元素。一些集合允许重复的元素(List),而其他的则不允许(Set)。有些是有序和无序的人。JDK没有提供这个接口的任何直接的实现:它提供更具体的子接口像
Set
和List
实现。此接口通常用于通过收集和操纵他们最大的共性是理想。
Collection 常用方法
public boolean add(E e)
: 把给定的对象添加到当前集合中 。(返回值为Boolean,通常都是true)public boolean remove(E e)
: 把给定的对象在当前集合中删除。public void clear()
:清空集合中所有的元素。(元素被清空了,但是集合还在)public boolean contains(Object obj)
: 判断当前集合中是否包含给定的对象。public boolean isEmpty()
: 判断当前集合是否为空。public int size()
: 返回集合中元素的个数。public Object[] toArray()
: 把集合中的元素,存储到数组中
操作
public class CollectionDemo {
public static void main(String[] args) {
// 创建集合
Collection coll =new ArrayList();
// 添加元素 boolean add(E e)
coll.add("AAA");
coll.add("BBB");
coll.add("CCC");
System.out.println("元素的个数"+coll.size());//元素的个数3
System.out.println("查看添加的元素"+coll); //[AAA, BBB, CCC]
// 删除元素
coll.remove("AAA");
System.out.println("删除后的结果"+coll);
// 清空集合
coll.clear();
System.out.println("清空后的结果"+coll);
// 遍历:用增强for 迭代器
coll.add("AAA");
coll.add("BBB");
coll.add("CCC");
for (Object collection : coll) {
System.out.println(collection);
}
// 迭代器
Iterator iterator = coll.iterator();
while (iterator.hasNext()){
Object next = iterator.next();
System.out.println(next);
}
}
}
List接口
java.util.List
接口继承自Collection
接口,是单列集合的一个重要分支,习惯性地会将实现了List
接口的对象称为List集合。
在List集合中允许出现重复的元素,所有的元素是以一种线性方式进行存储的,在程序中可以通过索引来访问集合中的指定元素。另外,List集合还有一个特点就是元素有序,即元素的存入顺序和取出顺序一致。
一个有序集合(也被称为序列)。此接口的用户在列表中的每个元素都被插入的地方有精确的控制。用户可以通过它们的整数索引(在列表中的位置)访问元素,并在列表中搜索元素。
与设置不同的是,列表通常允许重复元素。更正式,通常允许列表元素`e1`和`e2`这样`e1.equals(e2)`对,他们通常允许多个null元素是否允许null元素在所有。这并不是不可想象的,有人可能希望实现一个禁止重复的列表,通过抛出运行时异常,当用户试图插入它们,但我们希望这种用法是罕见的。
List接口三大特点:
有序——指的是存放的顺序,不是字母顺序!
带索引——根据索引来操作集合
可重复——可以存放重复的元素,equals来比较
List接口中常用方法
List作为Collection集合的子接口,不但继承了Collection接口中的全部方法,而且还增加了一些根据元素索引来操作集合的特有方法,如下:
public void add(int index, E element)
: 将指定的元素,添加到该集合中的指定位置上。public E get(int index)
:返回集合中指定位置的元素。public E remove(int index)
: 移除列表中指定位置的元素, 返回的是被移除的元素。public E set(int index, E element)
:用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
操作
public class ListDemo {
public static void main(String[] args) {
List list =new ArrayList();
list.add("BBB");
list.add("AAA");
list.add("CCC");
list.add(0,"First");//指定索引的添加
System.out.println("添加元素:"+ list);
list.remove("AAA");
System.out.println("删除元素AAA"+list);
list.remove(1);//指定索引的删除
System.out.println("指定索引的删除"+list);
ListIterator listIterator = list.listIterator();
while(listIterator.hasNext()){
Object next = listIterator.next();
int i = listIterator.nextIndex();
System.out.println(i+":"+next);
}
//逆向遍历
System.out.println("--------------------------");
while(listIterator.hasPrevious()){
Object previous = listIterator.previous();
int i = listIterator.previousIndex();
System.out.println(i+":"+previous);
}
for (Object o : list) {
System.out.println(o);
}
}
}
对数字的操作,自动装箱,变成对象再操作
public class ListDemo02 {
public static void main(String[] args) {
List list =new ArrayList();
list.add(111);
list.add(222);
System.out.println(list);
list.remove((Object) 111);
System.out.println(list);
}
}
ArrayList
java.util.ArrayList
集合数据存储的结构**是数组结构。元素增删慢,查找快**,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList
是最常用的集合。
LinkedList集合
java.util.LinkedList
集合数据存储的结构是**链表结构。增删快,查找慢**
![image-20210529215139813](https://gitee.com/qhzeng/markdown/raw/master/image/image-20210529215139813.png)
Set接口
java.util.Set
接口和java.util.List
接口一样,同样继承自Collection
接口,它与Collection
接口中的方法基本一致,并没有对Collection
接口进行功能上的扩充,只是比Collection
接口更加严格了。与List
接口不同的是,Set
接口都会以某种规则保证存入的元素不出现重复。
Set接口的特点
无序
无索引——不能按索引遍历
元素不可重复
操作
public class SetDemo {
public static void main(String[] args) {
Set<String> set =new HashSet<String>();
set.add("AAA");
set.add("XXX");
set.add("BBB");
System.out.println(set);//[AAA, BBB, XXX]
set.add("XXX"); //元素不重复
System.out.println(set); //[AAA, BBB, XXX]
set.remove("XXX");
System.out.println(set); //[AAA, BBB]
// 遍历
System.out.println("------------");
for (String s : set) {
System.out.println(s);
}
System.out.println("------------");
Iterator<String> iterator = set.iterator();
while(iterator.hasNext()){
String next = iterator.next();
System.out.println(next);
}
}
}
HashSet
HashSet
是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存储和查找性能。保证元素唯一性的方式依赖于:hashCode
与equals
方法。
- 该类实现了
Set
接口,通过一个哈希表支持(实际上是一个HashMap
实例)。
特点
底层数据结构是HashMap,HashSet这个类实现了Set集合,实际为一个HashMap的实例。
对集合的迭代顺序不做保证,不保证存储和取出的元素顺序一致
没有带索引的方法,所以不能使用普通for循环遍历
源码:
public HashSet() {
map = new HashMap<>();
}
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
操作:
public class HashSetDemo {
public static void main(String[] args) {
HashSet<String> hashSet = new HashSet<String>();
hashSet.add("AAA");
hashSet.add("XXX");
hashSet.add("BBB");
System.out.println(hashSet);
for (String s : hashSet) {
System.out.println(s);
}
}
}
HashSet集合存储数据的结构(哈希表)
在JDK1.8之前,哈希表底层采用数组+链表实现,即使用数组处理冲突,同一hash值的链表都存储在一个数组里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而
JDK1.8后,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
JDK1.8引入红黑树大程度优化了HashMap的性能,那么对于我们来讲保证HashSet集合元素的唯一,其实就是根据对象的hashCode和equals方法来决定的。如果我们往集合中存放自定义的对象,那么保证其唯一,就必须复写hashCode和equals方法建立属于当前对象的比较方式。
LinkedHashSet
我们知道HashSet保证元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序,怎么办呢?
在HashSet下面有一个子类java.util.LinkedHashSet
,它是链表和哈希表组合的一个数据存储结构。(数组+链表+红黑树 额外加了一条链表)
注意:这里的顺序指的是add的顺序,并非数据的顺序
public class LinkedHashSetDemo {
public static void main(String[] args) {
Set<String> set = new LinkedHashSet<String>();
set.add("bbb");
set.add("aaa");
set.add("abc");
set.add("bbc");
Iterator<String> it = set.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
结果:
bbb
aaa
abc
bbc
TreeSet
按照一定顺序来存储
构造方法 Constructor and Description
TreeSet()
构造一个新的、空的树集,根据其元素的自然排序进行排序。
TreeSet(Collection<? extends E> c)
构造一个新的树集包含在指定集合的元素,根据其元素的自然排序排序。
TreeSet(Comparator<? super E> comparator)
构造一个新的、空的树集,根据指定的比较器进行排序。
TreeSet(SortedSet<E> s)
构造一个包含相同元素的新树集,并使用相同的排序作为指定的排序集。
Map集合
Map
Collection
中的集合,元素是孤立存在的(理解为单身),向集合中存储元素采用一个个元素的方式存储。Map
中的集合,元素是成对存在的(理解为夫妻)。每个元素由**键与值两部分**组成,通过键可以找对所对应的值。Collection
中的集合称为单列集合,Map
中的集合称为双列集合。- 需要注意的是,
Map
中的集合**不能包含重复的键,值可以重复**;每个键只能对应一个值。
Map的常用子类
!
通过查看Map接口描述,看到Map有多个子类,这里我们主要讲解常用的HashMap集合、LinkedHashMap集合。
- HashMap<K,V>:存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
- LinkedHashMap<K,V>:HashMap下有个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构。通过链表结构可以保证元素的存取顺序一致;通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
- TreeMap<K,V>:TreeMap集合和Map相比没有特有的功能,底层的数据结构是红黑树;可以对元素的**键进行排序,排序方式有两种:自然排序和比较器排序
tips:Map接口中的集合都有两个泛型变量<K,V>,在使用时,要为两个泛型变量赋予数据类型。两个泛型变量<K,V>的数据类型可以相同,也可以不同。
常用方法
Map接口中定义了很多方法,常用的如下:
-
public V put(K key, V value)
: 把指定的键与指定的值添加到Map集合中。 -
public V remove(Object key)
: 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。 -
public V get(Object key)
根据指定的键,在Map集合中获取对应的值。 -
public Set<K> keySet()
: 获取Map集合中所有的键,存储到Set集合中。 -
public Set<Map.Entry<K,V>> entrySet()
: 获取到Map集合中所有的键值对对象的集合(Set集合)。 -
public boolean containKey(Object key)
:判断该集合中是否有此键。
Map的遍历
方式1:键找值方式
通过元素中的键,获取键所对应的值
分析步骤:
- 获取Map中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键。方法提示:
keyset()
- 遍历键的Set集合,得到每一个键。
- 根据键,获取键所对应的值。方法提示:
get(K key)
方式2:键值对方式
即通过集合中每个键值对(Entry)对象,获取键值对(Entry)对象中的键与值。
Entry键值对对象:
我们已经知道,Map
中存放的是两种对象,一种称为key(键),一种称为value(值),它们在在Map
中是一一对应关系,这一对对象又称做Map
中的一个Entry(项)
。Entry
将键值对的对应关系封装成了对象。即键值对对象,这样我们在遍历Map
集合时,就可以从每一个键值对(Entry
)对象中获取对应的键与对应的值。
在Map集合中也提供了获取所有Entry对象的方法:
public Set<Map.Entry<K,V>> entrySet()
: 获取到Map集合中所有的键值对对象的集合(Set集合)。
获取了Entry对象 , 表示获取了一对键和值,那么同样Entry中 , 分别提供了获取键和获取值的方法:
public K getKey()
:获取Entry对象中的键。public V getValue()
:获取Entry对象中的值。
操作:
public class MapDemo {
public static void main(String[] args) {
Map<String,Integer> map =new HashMap<>();
//插入
map.put("AAA",11);
map.put("BBB",11);
map.put("CCC",11);
map.put("DDD",11);
map.put(null,11);
map.put("XXX",null);
System.out.println(map);
//获取:通过key来获取value
System.out.println( map.get("AAA"));
//遍历1:先获取所有key——keySet(),再用key来获取value再遍历get(key)
Set<String> set = map.keySet();
for (String string : set) {
System.out.println(string+":"+map.get(string));
}
System.out.println("------------------");
//遍历2:map.entrySet();获得键值对对象,再用getKey,getValue分别获得键值对
Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
for (Map.Entry<String, Integer> entry : entrySet) {
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
}
HashMap存储自定义类型
public class Demo01 {
public static void main(String[] args) {
demo01();
}
private static void demo02() {
HashMap<Integer,Person> map =new HashMap<>();
map.put(3,new Person("ZQH",18));
map.put(4,new Person("AAA",19));
map.put(5,new Person("BBB",20));
map.put(3,new Person("ZQH",2222));
System.out.println(map);
Set<Map.Entry<Integer, Person>> set = map.entrySet();
for (Map.Entry<Integer, Person> entry : set) {
Integer key = entry.getKey();
Person value = entry.getValue();
System.out.println(key+"+"+value);
}
}
private static void demo01() {
HashMap<Person , Integer> map = new HashMap<>();
map.put(new Person("ZQH",18),3);
map.put(new Person("AAA",19),4);
map.put(new Person("BBB",20),5);
map.put(new Person("ZQH",18),4);
System.out.println(map);
Set<Map.Entry<Person, Integer>> set = map.entrySet();
for (Map.Entry<Person, Integer> entry : set) {
Person key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+","+value);
}
}
}
LinkedHashMap
有序的HashMap——顺序指的是put的顺序
public class Demo01 {
public static void main(String[] args) {
demo01();
}
private static void demo01() {
HashMap<String,String> map= new HashMap<>();
map.put("QQQ","123 ");
map.put("LLL","123");
map.put("AAA","123");
map.put("BBB","123");
map.put(null,null);
System.out.println(map);
LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("CCC","123");
linkedHashMap.put("AAA","123");
linkedHashMap.put("BBB","123");
System.out.println(linkedHashMap);
}
}
附录:API文档
Collection
boolean add(E e)
确保此集合包含指定的元素(可选操作)。
boolean addAll(Collection<? extends E> c)
将指定集合中的所有元素添加到这个集合(可选操作)。
void clear()
从这个集合中移除所有的元素(可选操作)。
boolean contains(Object o)
返回 true如果集合包含指定元素。
boolean containsAll(Collection<?> c)
返回 true如果这个集合包含指定集合的所有元素。
boolean equals(Object o)
将指定的对象与此集合进行比较,以进行相等性。
int hashCode()
返回此集合的哈希代码值。
boolean isEmpty()
返回 true如果集合不包含任何元素。
Iterator<E> iterator()
返回此集合中的元素的迭代器。
default Stream<E> parallelStream()
返回一个可能并行 Stream与集合的来源。
boolean remove(Object o)
从这个集合中移除指定元素的一个实例,如果它是存在的(可选操作)。
boolean removeAll(Collection<?> c)
删除此集合中包含的所有元素(可选操作)的所有元素(可选操作)。
default boolean removeIf(Predicate<? super E> filter)
删除满足给定谓词的这个集合的所有元素。
boolean retainAll(Collection<?> c)
仅保留包含在指定集合中的这个集合中的元素(可选操作)。
int size()
返回此集合中的元素的数目。
default Spliterator<E> spliterator()
创建此集合中的元素的 Spliterator。
default Stream<E> stream()
返回一个序列 Stream与集合的来源。
Object[] toArray()
返回包含此集合中所有元素的数组。
<T> T[] toArray(T[] a)
返回包含此集合中所有元素的数组;返回数组的运行时类型是指定的数组的运行时类型。
List
boolean add(E e)
将指定的元素到这个列表的末尾(可选操作)。
void add(int index, E element)
在列表中指定的位置上插入指定的元素(可选操作)。
boolean addAll(Collection<? extends E> c)
追加指定集合的所有元素到这个列表的末尾,按他们的指定集合的迭代器返回(可选操作)。
boolean addAll(int index, Collection<? extends E> c)
将指定的集合中的所有元素插入到指定位置的列表中(可选操作)。
void clear()
从这个列表中移除所有的元素(可选操作)。
boolean contains(Object o)
返回 true如果这个列表包含指定元素。
boolean containsAll(Collection<?> c)
返回 true如果这个列表包含指定集合的所有元素。
boolean equals(Object o)
将指定的对象与此列表进行比较,以进行相等性。
E get(int index)
返回此列表中指定位置的元素。
int hashCode()
返回此列表的哈希代码值。
int indexOf(Object o)
返回此列表中指定元素的第一个出现的索引,或-如果此列表不包含元素,或- 1。
boolean isEmpty()
返回 true如果此列表不包含元素。
Iterator<E> iterator()
在这个列表中的元素上返回一个正确的顺序。
int lastIndexOf(Object o)
返回此列表中指定元素的最后一个发生的索引,或-如果此列表不包含元素,或- 1。
ListIterator<E> listIterator()
返回列表元素的列表迭代器(在适当的顺序)。
ListIterator<E> listIterator(int index)
在列表中的元素上返回列表迭代器(在适当的顺序),从列表中的指定位置开始。
E remove(int index)
移除此列表中指定位置的元素(可选操作)。
boolean remove(Object o)
从该列表中移除指定元素的第一个发生,如果它是存在的(可选操作)。
boolean removeAll(Collection<?> c)
从这个列表中移除包含在指定集合中的所有元素(可选操作)。
default void replaceAll(UnaryOperator<E> operator)
用将运算符应用到该元素的结果替换此列表中的每个元素。
boolean retainAll(Collection<?> c)
仅保留包含在指定集合中的列表中的元素(可选操作)。
E set(int index, E element)
用指定元素替换此列表中指定位置的元素(可选操作)。
int size()
返回此列表中元素的数目。
default void sort(Comparator<? super E> c)
分类列表使用提供的 Comparator比较元素。
default Spliterator<E> spliterator()
创建此列表中的元素的 Spliterator。
List<E> subList(int fromIndex, int toIndex)
返回一个视图之间的指定 fromIndex,包容,和 toIndex这份名单的部分。 (左闭右开)
Object[] toArray()
返回一个数组,包含在这个列表中的所有元素在适当的顺序(从第一个到最后一个元素)。
<T> T[] toArray(T[] a)
返回一个数组,包含在这个列表中的所有元素在适当的顺序(从第一到最后一个元素);返回数组的运行时类型是指定的数组的运行时类型。
Set
boolean add(E e)
如果没有当前(可选操作),则将指定的元素添加到该集合中。
boolean addAll(Collection<? extends E> c)
如果没有当前(可选操作),将指定集合中的所有元素添加到该集合中。
void clear()
从这个集合中移除所有的元素(可选操作)。
boolean contains(Object o)
如果这套 true返回包含指定的元素。
boolean containsAll(Collection<?> c)
如果这套 true返回包含指定集合的所有元素。
boolean equals(Object o)
将指定的对象与此设置的相等性进行比较。
int hashCode()
返回此组的哈希代码值。
boolean isEmpty()
返回 true如果这个集合不包含元素。
Iterator<E> iterator()
返回此集合中元素的迭代器。
boolean remove(Object o)
如果当前(可选操作),则从该集合中移除指定的元素。
boolean removeAll(Collection<?> c)
从这个集合中移除包含在指定集合中的所有元素(可选操作)。
boolean retainAll(Collection<?> c)
仅保留包含在指定集合中的此集合中的元素(可选操作)。
int size()
返回该集合中元素个数(其基数)。
default Spliterator<E> spliterator()
在这个集合中的元素创建一个 Spliterator。
Object[] toArray()
返回一个包含此集合中所有元素的数组。
<T> T[] toArray(T[] a)
返回包含此集合中的所有元素的数组;返回的数组的运行时类型是指定的数组的运行时类型。
Map
void clear()
从这个映射中移除所有的映射(可选操作)。
default V compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
试图计算出指定键和当前的映射值的映射(或 null如果没有当前映射)。
default V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)
如果指定的键是不是已经与价值相关的(或映射到 null),尝试使用给定的映射功能,进入到这个Map除非 null计算其价值。
default V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
如果指定键的值是存在和非空的,尝试计算一个新的映射,给出了键和它当前的映射值。
boolean containsKey(Object key)
返回 true如果这Map包含一个指定的键映射。
boolean containsValue(Object value)
返回 true如果映射到指定的值的一个或多个键。
Set<Map.Entry<K,V>> entrySet()
返回一个 Set视图的映射包含在这个Map。
boolean equals(Object o)
将指定的对象与此映射的相等性进行比较。
default void forEach(BiConsumer<? super K,? super V> action)
在该映射中的每个条目执行给定的操作,直到所有的条目被处理或操作抛出异常。
V get(Object key)
返回指定的键映射的值,或 null如果这个Map不包含的键映射。
default V getOrDefault(Object key, V defaultValue)
返回指定的键映射的值,或 defaultValue如果这个Map不包含的键映射。
int hashCode()
返回此映射的哈希代码值。
boolean isEmpty()
返回 true如果这个Map不包含键值的映射。
Set<K> keySet()
返回一个 Set的关键视图包含在这个Map。
default V merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)
如果指定的键已与值相关联的值或与空值相关联的,则将其与给定的非空值关联。
V put(K key, V value)
将指定的值与此映射中的指定键关联(可选操作)。
void putAll(Map<? extends K,? extends V> m)
从指定的映射到这个Map(可选操作)复制所有的映射。
default V putIfAbsent(K key, V value)
如果指定的键是不是已经与价值相关的(或映射到 null)将其与给定的值并返回 null,否则返回当前值。
V remove(Object key)
如果存在(可选操作),则从该Map中移除一个键的映射。
default boolean remove(Object key, Object value)
仅当它当前映射到指定的值时,为指定的键移除条目。
default V replace(K key, V value)
仅当它当前映射到某一值时,替换指定的键的条目。
default boolean replace(K key, V oldValue, V newValue)
仅当当前映射到指定的值时,替换指定的键的条目。
default void replaceAll(BiFunction<? super K,? super V,? extends V> function)
将每个条目的值替换为在该项上调用给定函数的结果,直到所有的条目都被处理或函数抛出异常。
int size()
返回这个映射中的键值映射的数目。
Collection<V> values()
返回一个 Collection视图的值包含在这个Map。
将其与给定的非空值关联。
V put(K key, V value)
将指定的值与此映射中的指定键关联(可选操作)。
void putAll(Map<? extends K,? extends V> m)
从指定的映射到这个Map(可选操作)复制所有的映射。
default V putIfAbsent(K key, V value)
如果指定的键是不是已经与价值相关的(或映射到 null)将其与给定的值并返回 null,否则返回当前值。
V remove(Object key)
如果存在(可选操作),则从该Map中移除一个键的映射。
default boolean remove(Object key, Object value)
仅当它当前映射到指定的值时,为指定的键移除条目。
default V replace(K key, V value)
仅当它当前映射到某一值时,替换指定的键的条目。
default boolean replace(K key, V oldValue, V newValue)
仅当当前映射到指定的值时,替换指定的键的条目。
default void replaceAll(BiFunction<? super K,? super V,? extends V> function)
将每个条目的值替换为在该项上调用给定函数的结果,直到所有的条目都被处理或函数抛出异常。
int size()
返回这个映射中的键值映射的数目。
Collection<V> values()
返回一个 Collection视图的值包含在这个Map。