Java集合详解

Java基础-集合

1.Java集合框架

img
下面是简化图:
在这里插入图片描述

​ 在介绍这张图之前,先来了解下Java集合的设计思路。

1.1集合接口与实现分离

​ 以队列这种常见的数据结构来说明Java是如何分离接口(implementation)与实现的。
在这里插入图片描述

  1. Queue接口继承自Collection接口;
  2. Queue接口有子接口;
  3. 上面的实现类大多是实现子接口,像ArrayDeque是Deque< E >的实现。

下面以ArrauDeque的实现过程来举栗zi

队列接口的基本形式为:

public interface Queue<E>{
        void add(E element);
        E remove();
        int size();
    }

Qeue的子接口Deque接口

public interface Deque<E> extends Queue<E>{
    void addLast(E e);
    boolean offerFirst(E e);
}
//它新增了一些自己的方法

ArrayDeque是Deque的实现类:

public class ArrayDeque<E> extends AbstractCollection<E>
                           implements Deque<E>, Cloneable, Serializable

新建一个ArrayDeque对象使用:

ArrayDeque<Object> objects = new ArrayDeque<>();

1.2Colleaction接口

Collection中有两个基本方法

public interface Collection<E> extends Iterable<E>{
    boolean add(E element);
    Iterator<E> iterator();
    //返回一个实现了Iterraator接口的对象
}

1.3迭代器

Iterraator接口中包含以下4个方法:

default voidforEachRemaining(Consumer<? super E> action) 对每个剩余元素执行给定的操作,直到所有元素都被处理或动作引发异常。
booleanhasNext() 如果迭代具有更多元素,则返回 true
Enext() 返回迭代中的下一个元素。
default voidremove() 从底层集合中删除此迭代器返回的最后一个元素(可选操作)。

​ 我们平时常用的遍历集合中的元素的方法:

    List<Integer> list=new ArrayList<>();
        Iterator<Integer> iterator = list.iterator(); 
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

1.4Collection中的常用方法

booleanadd(E e) 将一个元素添加到集合中,如果由于这个调用改变了集合,则返回true
booleanaddAll(Collection<? extends E> c) 将指定集合中的所有元素添加到此集合(可选操作)。
voidclear() 从此集合中删除所有元素(可选操作)。
booleancontains(Object o) 如果此集合包含指定的元素,则返回 true
booleancontainsAll(Collection<?> c) 如果此集合包含指定 集合中的所有元素,则返回true。
booleanequals(Object o) 将指定的对象与此集合进行比较以获得相等性。
inthashCode() 返回此集合的哈希码值。
booleanisEmpty() 如果此集合不包含元素,则返回 true
Iterator<E>iterator() 返回此集合中的元素的迭代器。
default Stream<E>parallelStream() 返回可能并行的 Stream与此集合作为其来源。
booleanremove(Object o) 从该集合中删除指定元素的单个实例(如果存在)(可选操作)。
booleanremoveAll(Collection<?> c) 删除指定集合中包含的所有此集合的元素(可选操作)。
default booleanremoveIf(Predicate<? super E> filter) 删除满足给定谓词的此集合的所有元素。
booleanretainAll(Collection<?> c) 仅保留此集合中包含在指定集合中的元素(可选操作)。
intsize() 返回此集合中的元素数。
default Spliterator<E>spliterator() 创建一个Spliterator在这个集合中的元素。
default Stream<E>stream() 返回以此集合作为源的顺序 Stream
Object[]toArray() 返回一个包含此集合中所有元素的数组。
<T> T[]toArray(T[] a) 返回包含此集合中所有元素的数组; 返回的数组的运行时类型是指定数组的运行时类型。

1.5集合框架的接口

序号接口描述
1Collection 接口 Collection 是最基本的集合接口,一个 Collection 代表一组 Object,即 Collection 的元素, Java不提供直接继承自Collection的类,只提供继承于的子接口(如List和set)。Collection 接口存储一组不唯一,无序的对象。
2List 接口 List接口是一个有序的 Collection,使用此接口能够精确的控制每个元素插入的位置,能够通过索引(元素在List中位置,类似于数组的下标)来访问List中的元素,第一个元素的索引为 0,而且允许有相同的元素。List 接口存储一组不唯一,有序(插入顺序)的对象。
3Set Set 具有与 Collection 完全一样的接口,只是行为上不同,Set 不保存重复的元素。Set 接口存储一组唯一,无序的对象。
4SortedSet 继承于Set保存有序的集合。
5Map Map 接口存储一组键值对象,提供key(键)到value(值)的映射。
6Map.Entry 描述在一个Map中的一个元素(键/值对)。是一个 Map 的内部接口。
7SortedMap 继承于 Map,使 Key 保持在升序排列。
8Enumeration 这是一个传统的接口和定义的方法,通过它可以枚举(一次获得一个)对象集合中的元素。这个传统接口已被迭代器取代。

2.具体集合

序号类描述
1AbstractCollection 实现了大部分的集合接口。
2AbstractList 继承于AbstractCollection 并且实现了大部分List接口。
3AbstractSequentialList 继承于 AbstractList ,提供了对数据元素的链式访问而不是随机访问。
4LinkedList 该类实现了List接口,允许有null(空)元素。主要用于创建链表数据结构,该类没有同步方法,如果多个线程同时访问一个List,则必须自己实现访问同步,解决方法就是在创建List时候构造一个同步的List。例如:List list=Collections.synchronizedList(newLinkedList(...));LinkedList 查找效率低。
5ArrayList 该类也是实现了List的接口,实现了可变大小的数组,随机访问和遍历元素时,提供更好的性能。该类也是非同步的,在多线程的情况下不要使用。ArrayList 增长当前长度的50%,插入删除效率低。
6AbstractSet 继承于AbstractCollection 并且实现了大部分Set接口。
7HashSet 该类实现了Set接口,不允许出现重复元素,不保证集合中元素的顺序,允许包含值为null的元素,但最多只能一个。
8LinkedHashSet 具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。
9TreeSet 该类实现了Set接口,可以实现排序等功能。
10AbstractMap 实现了大部分的Map接口。
11HashMap HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。 该类实现了Map接口,根据键的HashCode值存储数据,具有很快的访问速度,最多允许一条记录的键为null,不支持线程同步。
12TreeMap 继承了AbstractMap,并且使用一颗树。
13WeakHashMap 继承AbstractMap类,使用弱密钥的哈希表。
14LinkedHashMap 继承于HashMap,使用元素的自然顺序对元素进行排序.
15IdentityHashMap 继承AbstractMap类,比较文档时使用引用相等。

​ 除了以Map结尾的类之外,其他类都实现了Collection接口;以Map结尾的类则实现了Map接口。

2.1链表

​ 数组以及动态的ArrarList的缺陷很明显,就是删除数组中的一个元素开销比较大,因为被删除元素之后的元素都需要向前挪动一位。为解决这一情况,引入了链表这一数据结构(LinkedList类)。且在Java中,所有链表都是双向链接的。
在这里插入图片描述

2.2ListIterator接口

​ List< E >接口中有一个listIterator方法,可以返回一个列表迭代器,用来访问列表中的元素。

voidadd(E e) 将指定的元素插入列表(可选操作)。
booleanhasNext() 返回 true如果遍历正向列表,列表迭代器有多个元素。
booleanhasPrevious() 返回 true如果遍历反向列表,列表迭代器有多个元素。
Enext() 返回列表中的下一个元素,并且前进光标位置。
intnextIndex() 返回随后调用 next()返回的元素的索引。
Eprevious() 返回列表中的上一个元素,并向后移动光标位置。
intpreviousIndex() 返回由后续调用 previous()返回的元素的索引。
voidremove() 从列表中删除由 next()previous()返回的最后一个元素(可选操作)。
voidset(E e)指定的元素替换由 next()previous()返回的最后一个元素(可选操作)。

2.3数组列表

​ ArrayList类不同于链表,该数据结构便于随机地访问每个元素,该类也实现了List接口。ArrayList封装了一个动态再分配的对象数组。

动态再分配

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

动态扩容原理详解

2.4散列集(Set)

为什么引入散列集:

​ 数组和链表虽然可以查找指定元素,但是我们必须要知道指定元素的位置,否则就需要访问所有的元素,直到找到为止。而散列表可以用于快速地查找对象。

​ 散列表为每个对象计算一个整数,称为散列码。又因为每个整数对应一个散列码,所以Set集合中的元素是唯一的。

散列表的实现

在这里插入图片描述

java.util.HashSet< E >

booleanadd(E e) 将指定的元素添加到此集合(如果尚未存在)。
voidclear() 从此集合中删除所有元素。
Objectclone() 返回此 HashSet实例的浅层副本:元素本身不被克隆。
booleancontains(Object o) 如果此集合包含指定的元素,则返回 true
booleanisEmpty() 如果此集合不包含元素,则返回 true
Iterator<E>iterator() 返回此集合中元素的迭代器。
booleanremove(Object o) 如果存在,则从该集合中删除指定的元素。
intsize() 返回此集合中的元素数(其基数)。
Spliterator<E>spliterator() 在此集合中的元素上创建*late-binding故障快速* Spliterator

2.5树集

​ TreeSet与散列集很相似,最大区别在于树集是一个有序集合。可以对按照任意顺序插入的元素自动排序。当然前提是元素必须实现Comparator接口。

下面以String对象为例,当然对于自定义的实体类,只要实现Comparator接口,也是可以排序的。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence
    
====================================
    
public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

TreeSet的类结构

public class TreeSet<E> extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable, java.io.Serializable

新版本的TreeSet没有实现SortedSet接口。

2.6队列

​ 队列可以高效地再尾部添加元素,头部删除元素;也就是元素满足先进后出

booleanadd(E e) 将指定的元素插入到此队列中,如果可以立即执行此操作,而不会违反容量限制, true在成功后返回 IllegalStateException如果当前没有可用空间,则抛出IllegalStateException。
Eelement() 检索,但不删除,这个队列的头。
booleanoffer(E e) 如果在不违反容量限制的情况下立即执行,则将指定的元素插入到此队列中。
Epeek() 检索但不删除此队列的头,如果此队列为空,则返回 null
Epoll() 检索并删除此队列的头,如果此队列为空,则返回 null
Eremove() 检索并删除此队列的头。

双端队列

​ 双端队列可以在头部和尾部都添加或删除元素。Java6中引入了Deque接口,ArrayDeque和LinkedList类都实现了这个接口。

优先队列

​ 优先队列中的元素可以按照任意的顺序插入,但会按照有序的顺序进行检索。即任意时刻调用remove()方法都会获得当前优先队列中的最小元素。因此优先队列常用于任务调度

3.映射

​ 在集合中,我们要查找一个元素,需要有所要查询的那个元素的准确副本。但是通常情况下,我们都是只知道元素的某些信息,希望获取与之关联的元素。而映射这种数据结构就是为此设计的。

​ 映射用于存放键/值对,提供了键,就能获取值。

3.1基本映射操作

Java类库中为映射提供了两个实现:HashMap与TreeMap,两者都实现了Map接口。

散列映射对键进行散列,而树映射是根据键的顺序将元素组织为一个搜索树,方便按照有序的顺序访问键。

V get(Object key)获取与键关联的值
default V getOrDefault(Object key, V defaultValue)返回到指定键所映射的值,或 defaultValue如果此映射包含该键的映射。
V put(K key, V value)将指定的值与该映射中的指定键相关联(可选操作)。
default void forEach(BiConsumer<? super K,? super V> action)对此映射中的每个条目执行给定的操作,直到所有条目都被处理或操作引发异常。
boolean containsKey(Object key)如果此映射包含指定键的映射,则返回 true 。

3.2映射视图

​ 映射的视图有三种,键集、值集、键值对集。获取分别对应下面的三种方法。

Set< K > ketSet()获取键集
Collection< V > values()获取值集
Set< Map,Entry > entrySet()获取键值对集
### Java集合框架详解 #### 什么是Java集合框架? Java集合框架是一组用于表示和操作集合的标准接口和类[^1]。它提供了一种统一的方式来处理常见的数据结构,如列表(List)、集(Set)和映射(Map)。这些数据结构可以帮助开发者更有效地管理对象。 #### List 接口及其实现 `List` 是一个有序的集合,允许重复元素。它的主要特点是可以通过索引来访问元素。以下是 `List` 的常见实现类: - **ArrayList**: 基于动态数组实现,适合频繁随机访问的场景[^2]。 - **LinkedList**: 双向链表实现,适合频繁插入和删除的操作。 ##### 示例代码: ```java import java.util.ArrayList; import java.util.List; public class ListExample { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("Apple"); list.add("Banana"); System.out.println(list.get(0)); // 输出 Apple } } ``` #### Set 接口及其实现 `Set` 不允许有重复的元素,并且不保证顺序。其常用实现包括: - **HashSet**: 提供快速查找功能,底层基于哈希表实现。 - **TreeSet**: 维护自然顺序或者通过比较器指定的顺序,支持排序操作。 ##### 示例代码: ```java import java.util.Set; import java.util.HashSet; public class SetExample { public static void main(String[] args) { Set<String> set = new HashSet<>(); set.add("Apple"); set.add("Banana"); System.out.println(set.contains("Apple")); // 输出 true } } ``` #### Map 接口及其实现 `Map` 存储的是键值对(key-value pairs),其中键唯一而值可以重复。常用的 `Map` 实现有: - **HashMap**: 底层采用哈希表实现,不允许 null 键和值。 - **TreeMap**: 使用红黑树实现,能够按照键的自然顺序或自定义顺序排列。 ##### 示例代码: ```java import java.util.Map; import java.util.HashMap; public class MapExample { public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("Apple", 1); map.put("Banana", 2); System.out.println(map.get("Apple")); // 输出 1 } } ``` --- #### 总结 Java集合框架的核心在于理解不同集合的特点以及适用场景。对于需要保持元素顺序的情况可以选择 `List`;如果希望去除重复项,则应考虑使用 `Set`;而对于键值关联的需求则更适合选用 `Map`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高冷小伙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值