带你认识:Java集合的"大家庭"

Posted 王明

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了带你认识: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 派系

  1. 有序 (存、取的顺序相同-怎么存,怎么取)
  2. 有索引(可以通过索引精准操作数据)
  3. 允许存储重复元素
  • ArrayList
    • 底层数据结构是:一个长度可变的数组(数组本身长度不可变), 初始化的长度是 10(可变原理: 通过对数组的复制进行扩容,扩容增长率: 50%)。
    • 线程不安全, 运行速度快
    • 查询速度快, 增删速度慢
  • LinkedList
    • 底层数据结构: 链表结构(采用对象之间的地址记录位置)
    • 线程不安全, 运行速度快
    • 查询速度慢, 增删速度快
  • Vector( Vector 被 ArrayList 取代)
    • 底层数据结构是一个长度可变的数组(和ArrayList一样,不同的是扩容增长率: 100%)。
    • 线程安全, 运行速度慢
    • 查询速度快, 增删速度慢

Set 派系

  1. 无序 (存、取顺序可能不一样)
  2. 无索引
  3. 不允许存储重复元素
  • HashSet(无序)

    • 单重链接列表
    • 底层数据结构:哈希表(实际上是一个HashMap实例, 根据底层源码可得: 底层是一个HashMap )
    • 线程不安全、运行速度快
      • LinkedHashSet(有序)
        • LinkedHashSet始于JDK1.4,Set始于JDK1.2
        • 双重链接列表, 底层基于链表的哈希表实现
        • 具有可预知迭代顺序(存、取顺序一致)
        • 线程不安全, 运行速度快,存取速度快
  • TreeSet(有序且唯一)

    • 底层数据结构基于: 红黑树
    • 可以对存储的元素进行排序
    • 线程不安全, 运行速度快

集合 Map 派系

  1. 采用了 Key-value键值对映射的方式进行存储。
  2. key是无序、唯一的,value是无序不唯一的。
  • HashMap(无序)

    • 底层数据结构:哈希表
    • 线程不安全,运行速度快,存取速度快
    • 允许 存储\'null\'值、\'null\'键
      • LinkedHashMap
        • 底层数据结构:哈希表
        • 键有迭代顺序(存、取顺序一致)
        • 线程不安全,运行速度快
  • TreeMap(有序)

    • 底层结构:红黑树(可以按照对象的自然顺序进行排序)
    • 键(对象):必须要有自然顺序,或采用比较器(作为键必须要有自然顺序或者使用了比较器,否则会报错)
    • 线程不安全,运行速度快
  • HashTable( 无序,HashTable 被 HashMap 取代)

    • 底层数据结构:哈希表
    • 键(对象):必须重写方法:hashCode()、equals()
    • 不允许存\'null\'( 键、值 都不允许为\'null\', 若存\'null\',编译时期不报错,运行时期会抛出空指针异常 )
    • 线程安全,运行速度慢
      • Properties(无序)
        • 底层数据结构:哈希表
        • 不允许重复键
        • 存、取顺序不确定(无序)
        • 线程安全,运行速度慢

常见的数据结构(数据存储方式)

栈:数据 先进 后出
队列:数据 先进 先出
数组:按照索引进行存储
链表:存储数据,按照地址的记录方式存储(前面记住后面的 或 后面记住前面的 依次类推)
树:存储的数据在容器中像树结构那样,对象可以排序 (红黑树)
哈希表:存储对象依赖对象的哈希值

Map集合的迭代(遍历)

迭代步骤

    1. 使用集合的方法: iterator() 获取迭代器对象(获取的是 Iterator 接口的实现类对象)。
    1. 使用迭代器对象, 调用方法 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:映射键值对 )

  1. Map 并不继承于 Collection 接口 ( Map 和 Collection 都是顶级接口 )
  2. Map 一个键对应一个值( 键不能重复, 值可以重复 )
  3. Map: 所有的子接口或实现类, 存储对象的时候, 每次存储两个对象(键 和 值)(add)
  4. Collection: 所有的子接口或实现类, 每次只能存储一个对象(值)(put)
  5. Map 是双列的, Collection 是单列的

Array(数组)和 ArrayList(集合)的区别

数组:Array

  • 表示形式:int[] array = new int[3] 或 int[] array = {1,2,3,4,5}
  • 数据:改、查。长度大小固定!在内存中是连续的,速度较快,操作简单

集合:ArrayList

  • 表示形式: ArrayList list = new ArrayList();
  • 数据:可 增、删、改、查。长度大小可动态增长

以上是关于带你认识:Java集合的"大家庭"的主要内容,如果未能解决你的问题,请参考以下文章

带你认识3个J.U.C组件扩展

带你认识3个J.U.C组件扩展

Java里面如何求两个集合的交集

Java并没有衰落.大家对它的认识才刚刚开始 Java8全新出发

Java并没有衰落.大家对它的认识才刚刚开始 Java8全新出发

带你认识UML