• Java 集合


    关于集合的详细介绍,推荐Java集合系列,以下是上面博客做的总结


    • Java集合是Java提供的工具包,包含了常用的数据结构:集合、链表、队列、栈、数组、映射等
    • Java各个集合也是和数组一样性质的元素容器,但是数组长度固定,集合长度可变
    • 集合存储的元素必须是引用数据类型,不能是基本数据类型

    Java集合工具包框架图:
    image

    简化图:
    image

    Collection(接口)

    image
    Collection是一个接口,是高度抽象出来的集合,它包含了集合的基本操作和属性;

    Collection接口的基本API

    abstract boolean         add(E object)
    abstract boolean         addAll(Collection<? extends E> collection)
    abstract void            clear()
    abstract boolean         contains(Object object)
    abstract boolean         containsAll(Collection<?> collection)
    abstract boolean         equals(Object object)
    abstract int             hashCode()
    abstract boolean         isEmpty()
    abstract Iterator<E>     iterator()
    abstract boolean         remove(Object object)
    abstract boolean         removeAll(Collection<?> collection)
    abstract boolean         retainAll(Collection<?> collection)
    abstract int             size()
    abstract <T> T[]         toArray(T[] array)
    abstract Object[]        toArray()
    

    为了方便,抽象出了AbstractCollection抽象类,它实现了Collection接口中绝大部分方法。
    因此在Collection的实现类中,可以通过继承这个抽象类省去重复编码

    它的主要两个分支是: ListSet ,同样,这两个接口也有着自己的抽象类



    List(接口)

    继承了Collection接口,是有序的一个队列,也称为序列。

    List中的每一个元素都有一个索引,索引从0开始然后依次递增1,因此可以对列表中每个元素进行精确控制和访问。

    和Set不同,List允许有重复的元素

    除了Collection中已有的API,新增的有:

    abstract void                add(int location, E object)
    abstract boolean             addAll(int location, Collection<? extends E> collection)
    abstract E                   get(int location)
    abstract int                 indexOf(Object object)
    abstract int                 lastIndexOf(Object object)
    abstract ListIterator<E>     listIterator(int location)
    abstract ListIterator<E>     listIterator()
    abstract E                   remove(int location)
    abstract E                   set(int location, E object)
    abstract List<E>             subList(int start, int end)
    

    ArrayList

    ArrayList 是一个数组队列,相当于动态数组。与Java中的数组相比,它的容量能动态增长。

    它继承于AbstractList,实现了的接口有:

    1. RandmoAccess接口,提供了随机访问功能
    2. Cloneable接口,能被克隆
    3. Serializable接口,支持序列化,能序列化传输

    ArrayList的API

    boolean             add(E object)
    boolean             addAll(Collection<? extends E> collection)
    void                clear()
    boolean             contains(Object object)
    boolean             containsAll(Collection<?> collection)
    boolean             equals(Object object)
    int                 hashCode()
    boolean             isEmpty()
    Iterator<E>         iterator()
    boolean             remove(Object object)
    boolean             removeAll(Collection<?> collection)
    boolean             retainAll(Collection<?> collection)
    int                 size()
    <T> T[]             toArray(T[] array)
    Object[]            toArray()
    void                add(int location, E object)
    boolean             addAll(int location, Collection<? extends E> collection)
    E                   get(int location)
    int                 indexOf(Object object)
    int                 lastIndexOf(Object object)
    ListIterator<E>     listIterator(int location)
    ListIterator<E>     listIterator()
    E                   remove(int location)
    E                   set(int location, E object)
    List<E>             subList(int start, int end)
    Object              clone()
    void                ensureCapacity(int minimumCapacity)
    void                trimToSize()
    void                removeRange(int fromIndex, int toIndex)
    

    ArrayList数据结构是数组结构,默认容量大小是10,当容量不够的时候会自动扩容,新的容量=(原始容量*3)/2 + 1

    ArrayList最大的特点:查找快增删慢

    ArrayList遍历方式
    1. 通过迭代器遍历
    Integer value = null;
    Iterator iter = list.iterator();
    while (iter.hasNext()) {
        value = (Integer)iter.next();
    }
    
    1. 通过for循环遍历
    Integer value = null;
    for (Integer integ:list) {
        value = integ;
    }
    
    1. 通过随机访问索引值遍历
    Integer value = null;
    int size = list.size();
    for (int i=0; i<size; i++) {
        value = (Integer)list.get(i);        
    }
    

    遍历ArrayList时,使用随机访问遍历效率最高,其次是for遍历,使用迭代器效率最低


    Vector

    Vector 是矢量队列,有相关增删改查等功能

    和ArrayList不同,Vector中的操作是线程安全

    它继承于AbstractList,实现了的接口有:

    1. RandmoAccess,提供了随机访问功能
    2. Cloneable接口,能被克隆
    3. Serializable接口,支持序列化,能序列化传输

    Vector的API

    synchronized boolean        add(E object)
                 void           add(int location, E object)
    synchronized boolean        addAll(Collection<? extends E> collection)
    synchronized boolean        addAll(int location, Collection<? extends E> collection)
    synchronized void           addElement(E object)
    synchronized int            capacity()
                 void           clear()
    synchronized Object         clone()
                 boolean        contains(Object object)
    synchronized boolean        containsAll(Collection<?> collection)
    synchronized void           copyInto(Object[] elements)
    synchronized E              elementAt(int location)
                 Enumeration<E> elements()
    synchronized void           ensureCapacity(int minimumCapacity)
    synchronized boolean        equals(Object object)
    synchronized E              firstElement()
                 E              get(int location)
    synchronized int            hashCode()
    synchronized int            indexOf(Object object, int location)
                 int            indexOf(Object object)
    synchronized void           insertElementAt(E object, int location)
    synchronized boolean        isEmpty()
    synchronized E              lastElement()
    synchronized int            lastIndexOf(Object object, int location)
    synchronized int            lastIndexOf(Object object)
    synchronized E              remove(int location)
                 boolean        remove(Object object)
    synchronized boolean        removeAll(Collection<?> collection)
    synchronized void           removeAllElements()
    synchronized boolean        removeElement(Object object)
    synchronized void           removeElementAt(int location)
    synchronized boolean        retainAll(Collection<?> collection)
    synchronized E              set(int location, E object)
    synchronized void           setElementAt(E object, int location)
    synchronized void           setSize(int length)
    synchronized int            size()
    synchronized List<E>        subList(int start, int end)
    synchronized <T> T[]        toArray(T[] contents)
    synchronized Object[]       toArray()
    synchronized String         toString()
    synchronized void           trimToSize()
    

    Vector的数据结构和ArrayList差不多,默认容量大小是10,当容量不够的时候会自动扩容,若容量增加系数 >0,则将容量的值增加“容量增加系数”;否则,将容量大小增加一倍

    Vector遍历方式
    1. 通过随机访问遍历
    Integer value = null;
    int size = vec.size();
    for (int i=0; i<size; i++) {
        value = (Integer)vec.get(i);        
    }
    
    1. 通过Enumeration遍历
    Integer value = null;
    Enumeration enu = vec.elements();
    while (enu.hasMoreElements()) {
        value = (Integer)enu.nextElement();
    }
    
    1. 通过for循环遍历
    Integer value = null;
    for (Integer integ:vec) {
        value = integ;
    }
    
    1. 通过迭代器循环遍历
    Integer value = null;
    int size = vec.size();
    for (int i=0; i<size; i++) {
        value = (Integer)vec.get(i);        
    }
    

    遍历Vector时,使用随机访问遍历效率最高,使用迭代器效率最低


    LinkedList

    LinkedList 是一个双向链表,也可以被当作堆栈队列双端队列

    它继承于AbstractSequentialList,实现了的接口有:

    1. List接口,能进行队列操作
    2. Deque接口,既能当作双端队列使用
    3. Cloneable接口,能被克隆
    4. Serializable接口,支持序列化,能序列化传输

    LinkedList的API

    boolean             add(E object)
    void                add(int location, E object)
    boolean             addAll(Collection<? extends E> collection)
    boolean             addAll(int location, Collection<? extends E> collection)
    void                addFirst(E object)
    void                addLast(E object)
    void                clear()
    Object              clone()
    boolean             contains(Object object)
    Iterator<E>         descendingIterator()
    E                   element()
    E                   get(int location)
    E                   getFirst()
    E                   getLast()
    int                 indexOf(Object object)
    int                 lastIndexOf(Object object)
    ListIterator<E>     listIterator(int location)
    boolean             offer(E o)
    boolean             offerFirst(E e)
    boolean             offerLast(E e)
    E                   peek()
    E                   peekFirst()
    E                   peekLast()
    E                   poll()
    E                   pollFirst()
    E                   pollLast()
    E                   pop()
    void                push(E e)
    E                   remove()
    E                   remove(int location)
    boolean             remove(Object object)
    E                   removeFirst()
    boolean             removeFirstOccurrence(Object o)
    E                   removeLast()
    boolean             removeLastOccurrence(Object o)
    E                   set(int location, E object)
    int                 size()
    <T> T[]             toArray(T[] contents)
    Object[]            toArray()
    

    LinkedList数据结构是双向链表结构,没有初始大小,也没有扩容的机制,只在前面或后面新增就行

    ArrayList最大的特点:增删快查找慢

    LinkedList遍历方式:
    1. 通过for循环遍历
    for (Integer integ:list) {
        value = integ;
    }
    
    1. 通过remove遍历
    try {
        while(list.removeLast() != null);
        
        while(list.removeFirst() != null);
    } catch (NoSuchElementException e) {
    }
    
    1. 通过poll遍历
    while(list.pollLast() != null);
    或
    while(list.pollFirst() != null);
    
    1. 通过迭代器遍历
    Integer value = null;
    Iterator iter = list.iterator();
    while (iter.hasNext()) {
        value = (Integer)iter.next();
    }
    
    1. 通过快速随机遍历
    int size = list.size();
    for (int i=0; i<size; i++) {
        list.get(i);        
    }
    

    遍历LinkedList时,使用remove效率最高,但是会删除原始数据,只读取遍历应该使用for循环遍历,使用随机访问效率最低



    Set(接口)

    Set 是继承于Collection的接口。它是一个不允许有重复元素的集合

    AbstractSet 是一个抽象类,它继承于AbstractCollection,AbstractCollection实现了Set中的绝大部分函数,为Set的实现类提供了便利

    HashSet

    • HashSet是一个没有重复元素的集合,但是也是非同步的

      如果多个线程同时访问一个哈希 set,而其中至少一个线程修改了该 set,那么它必须 保持外部同步。这通常是通过对自然封装该 set 的对象执行同步操作来完成的。如果不存在这样的对象,则应该使用 Collections.synchronizedSet 方法来“包装” set。最好在创建时完成这一操作,以防止对该 set 进行意外的不同步访问

    • 本质是由HashMap实现,其中的操作函数实际上都是通过map实现的
    • 不保证元素的存储顺序,而且HashSet允许使用null元素。

    HashSet的主要API

    boolean         add(E object)
    void            clear()
    Object          clone()
    boolean         contains(Object object)
    boolean         isEmpty()
    Iterator<E>     iterator()
    boolean         remove(Object object)
    int             size()
    
    HashSet遍历方式:
    1. 通过迭代器循环遍历
    for(Iterator iterator = Iterator<String> it = set.iterator();
    while (it.hasNext()) {
      String str = it.next();
    }
    
    1. 通过for循环遍历
    for (String str : set) {
        System.out.println(str);
    }
    
    HashSet保证不重复的原理

    equalshashcode
    hashcode能根据对象,计算出并返回一个整数结果,如果对象相同,结果也会相同。
    HashSet的底层是用HashMap存储数据的,它会先计算出这个元素存储在map的位置。
    如果位置为空就会添加进去,
    如果不为空,则用equals方法比较元素是否相等,相等就不添加,不等则找个空位添加


    LinkedHashSet

    属于HashSet的子类,是链表和哈希表相组合的数据存储结构

    链表同时保证顺序一致


    TreeSet

    TreeSet是一个有序的集合,从创建或插入的时候就已经排好序。

    TreeSet基于TreeMap实现,元素支持2种排序方式:

    • 自然排序

      构造时使用API自带方法排序

    • Comparator比较器排序

      自定义类中实现Comparator接口,重写compare方法

    • 自定义实体类

      实体类实现comparable接口,重写compareTo方法

    比较规则:
    return 小于0时,放左边
    return 大于0时,放右边
    return 等于0时,放一个

    关于Comparator与Comparable

    able是排序接口,若一个类实现该接口,则代表该类支持排序(相当于内部比较器)
    tor是比较器,若一个类实现该接口,则一定要重写compareTo方法来支持排序

    当自定义排序写好之后,可以用sort进行排序

    Collections.sort(list)
    

    它会根据集合类型选择comparTo方法

    当需要再倒序的时候,可以用reverseOrder()方法

    Comparator<Student> c = Collections.reverseOrder();
    Collections.sort(list,c);
    

    TreeSet继承于AbstractSet,实现了的接口有:

    1. NavigableSet接口,能进行队列操作
    2. Cloneable接口,能被克隆
    3. Serializable接口,支持序列化,能序列化传输

    TreeSet的主要API

    boolean                   add(E object)
    boolean                   addAll(Collection<? extends E> collection)
    void                      clear()
    Object                    clone()
    boolean                   contains(Object object)
    E                         first()
    boolean                   isEmpty()
    E                         last()
    E                         pollFirst()
    E                         pollLast()
    E                         lower(E e)
    E                         floor(E e)
    E                         ceiling(E e)
    E                         higher(E e)
    boolean                   remove(Object object)
    int                       size()
    Comparator<? super E>     comparator()
    Iterator<E>               iterator()
    Iterator<E>               descendingIterator()
    SortedSet<E>              headSet(E end)
    NavigableSet<E>           descendingSet()
    NavigableSet<E>           headSet(E end, boolean endInclusive)
    SortedSet<E>              subSet(E start, E end)
    NavigableSet<E>           subSet(E start, boolean startInclusive, E end, boolean endInclusive)
    NavigableSet<E>           tailSet(E start, boolean startInclusive)
    SortedSet<E>              tailSet(E start)
    
    TreeSet遍历方式:
    1. 通过迭代器循环遍历
    for(Iterator iterator = Iterator<String> it = set.iterator();
    while (it.hasNext()) {
      String str = it.next();
    }
    
    1. 通过for循环遍历
    for (String str : set) {
        System.out.println(str);
    }
    
    TreeSet保证不重复的原理

    compareTo
    一般只需要实现Comparable接口或compareTo()方法就可以了
    但是自定义类的话推荐重写equals方法,可能compare结果为0,但equals却是false结果



    Map(接口)

    image
    Map是一个键值对映射接口,每个元素都由键与值两部分组成
    在映射中不能包含重复的键,一个键只能映射一个值

    Collection接口的基本API

    abstract void                 clear()
    abstract boolean              containsKey(Object key)
    abstract boolean              containsValue(Object value)
    abstract Set<Entry<K, V>>     entrySet()
    abstract boolean              equals(Object object)
    abstract V                    get(Object key)
    abstract int                  hashCode()
    abstract boolean              isEmpty()
    abstract Set<K>               keySet()
    abstract V                    put(K key, V value)
    abstract void                 putAll(Map<? extends K, ? extends V> map)
    abstract V                    remove(Object key)
    abstract int                  size()
    abstract Collection<V>        values()
    

    entrySet()用于返回键-值集的Set集合
    keySet()用于返回键集的Set集合
    values()用户返回值集的Collection集合
    因为Map中不能包含重复的键;每个键最多只能映射到一个值。所以,键-值集、键集都是Set,值集时Collection。

    同样,Map接口有一个骨干实现:AbstractMap类,以最大限度地减少实现此接口所需的工作

    遍历set的方式
    Map 接口提供三种collection 视图,允许以键集、值集或键-值映射关系集的形式查看某个映射的内容。

    • 键集:获取集合中所有的键,通过迭代集合用get()方法获得对应值
    Set< E > sets = maps.keySet();
    //遍历
    Iterator<String> it = sets.iterator();
    while(it.hasNext()){
        String key = it.next();//得到每一个key
        String value = map.get(key);//通过key获取对应的value
        System.out.println(key+"="+value);
    }
    
    • 值集:获取集合中所有的值
      (没有键和映射关系)
    Collection< E > collections =  maps.values();
    
    • 键值映射关系集:获取映射关系的set视图,通过迭代集合用getKey()、getValue()获得键和值
    Set< Map.Entry<K,V> > entries = maps.entrySet();
    //遍历
    Iterator< Map.Entry<K,V> > it = entries.iterator();
    while(it.hasNext()){
        //得到每一对对应关系
        Map.Entry<K,V> entry = it.next();
        //通过对应关系获取对应的key
        String key = entry.getKey();
        //通过对应关系获取对应的value
        String value = entry.getValue();
        
        System.out.println(key+"="+value);
    }
    

    虽然keySet和entrySet进行遍历能取得相同的结果,但是entrySet的性能明显比keySet要好,遍历速度也是最快的

    其中,大部分适用的entrySet的遍历方式为:

    Map<Integer, Integer> map = new HashMap<Integer, Integer>(); 
    for (Map.Entry<Integer, Integer> entry : map.entrySet()) { 
        System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); 
    }
    

    HashMap

    HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。

    HashMap 继承于AbstractMap,实现了:Map、Cloneable、erializable接口。

    HashMap 的实现不是同步的,这意味着它不是线程安全的。它的key、value都可以为null。
    此外,HashMap中的映射是无序的。

    HashMap的API

    void                 clear()
    Object               clone()
    boolean              containsKey(Object key)
    boolean              containsValue(Object value)
    Set<Entry<K, V>>     entrySet()
    V                    get(Object key)
    boolean              isEmpty()
    Set<K>               keySet()
    V                    put(K key, V value)
    void                 putAll(Map<? extends K, ? extends V> map)
    V                    remove(Object key)
    int                  size()
    Collection<V>        values()
    

    HashMap 的实例有两个参数影响其性能:“初始容量”“加载因子”
    容量:是哈希表中桶的数量,初始容量 只是哈希表在创建时的容量。
    加载因子:是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。

    通常,默认加载因子是 0.75 , 这是在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括 get 和 put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。


    LinkedHashMap

    属于HashMap的子类,是链表哈希表相组合的数据存储结构

    保证顺序一致


    TreeMap

    TreeMap 是一个有序的key-value集合,它是通过红黑树实现的。

    该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。
    TreeMap的基本操作 containsKey、get、put 和 remove 的时间复杂度是 log(n) 。
    另外,TreeMap是非同步的。
    它的iterator 方法返回的迭代器是fail-fastl的。

    TreeMap的API

    Entry<K, V>                ceilingEntry(K key)
    K                          ceilingKey(K key)
    void                       clear()
    Object                     clone()
    Comparator<? super K>      comparator()
    boolean                    containsKey(Object key)
    NavigableSet<K>            descendingKeySet()
    NavigableMap<K, V>         descendingMap()
    Set<Entry<K, V>>           entrySet()
    Entry<K, V>                firstEntry()
    K                          firstKey()
    Entry<K, V>                floorEntry(K key)
    K                          floorKey(K key)
    V                          get(Object key)
    NavigableMap<K, V>         headMap(K to, boolean inclusive)
    SortedMap<K, V>            headMap(K toExclusive)
    Entry<K, V>                higherEntry(K key)
    K                          higherKey(K key)
    boolean                    isEmpty()
    Set<K>                     keySet()
    Entry<K, V>                lastEntry()
    K                          lastKey()
    Entry<K, V>                lowerEntry(K key)
    K                          lowerKey(K key)
    NavigableSet<K>            navigableKeySet()
    Entry<K, V>                pollFirstEntry()
    Entry<K, V>                pollLastEntry()
    V                          put(K key, V value)
    V                          remove(Object key)
    int                        size()
    SortedMap<K, V>            subMap(K fromInclusive, K toExclusive)
    NavigableMap<K, V>         subMap(K from, boolean fromInclusive, K to, boolean toInclusive)
    NavigableMap<K, V>         tailMap(K from, boolean inclusive)
    SortedMap<K, V>            tailMap(K fromInclusive)
    


    扩容总结

    Collection 初始 扩容倍数 备注
    ArrayList 10 1.5x 新增的如果超过要扩容的大小,则容量为所需的最小容量
    LinkedList 无默认容量 不需要扩容 这是个链表结构,无需扩容
    Vector 10 2x 扩容方式代价太大,初始扩容效率低,频繁增长造成过多内存碎片
    HashSet 16 2x 加载因子是0.75,即当个数超过容量的0.75倍时会进行扩容
    HashMap 16 2x 加载因子也是0.75
    StringBuffer/Builder 16字符 2x +2


  • 相关阅读:
    学习Android有感!
    使用PHP-Barcode轻松生成条形码(一)
    php利用redis实现分页列表,新增,删除功能
    JS验证input输入框(字母,数字,符号,中文)正则实现
    mac 安装swoole扩展
    git 配置本地SSH秘钥
    lnmp 一键安装
    lnmp php版本升级
    NATAPP内网穿透,本地进行微信开发,支付开发,对象存储回调信息
    微信公众号二维码
  • 原文地址:https://www.cnblogs.com/zohnn/p/11260671.html
Copyright © 2020-2023  润新知