第10章、集合

第10章、集合

10.1、概述

  • 集合是Java中提供的一种容器,可以用来存储多个数据。
  • 集合和数组都是容器,区别如下:
    • 数组长度是固定的。集合的长度是可变的;
    • 数组中可以存储基本数据类型值,也可以存储对象,而集合中只能存储对象;
  • 集合分为两大系列:
    • Collection表示一组对象;
    • Map表示一组映射关系或键值对;

10.2、Collection

10.2.1、Collection的主要方法

1、添加元素
  • add(E 0bj):添加元素对象到当前集合;
  • addAll(Collection<? extends E> other):添加other集合中所有元素对象到当前集合中。
2、删除元素
  • boolean remove(Object obj):从当前集合中删除第一个找到的与obj对象equals返回true的元素;
  • boolean removeAll(Collection<?> coll):从当前集合中删除所有与coll相同的元素。
3、判断
  • boolean isEmpty():判断当前集合是否为空集合;
  • boolean contains(Object obj):判断当前集合中是否存在一个与obj对象equals返回true的元素;
  • boolean containsAll(Collection<?> c):判断c集合中是否在当前集合中都存在。
4、获取元素个数
  • int size():获取当前集合中实际存储的元素个数。
5、交集
  • boolean retainAll(Collection<?> coll):当前集合仅保留与c集合中元素相同的元素。
6、转为数组
  • Object[] toArray():返回包含当前集合中所有的元素数组。
7、迭代器
  • public Iterator iterator():获取集合对应的迭代器,用来遍历集合中的元素。
  • 迭代器的常用方法:
    • public E next():返回迭代的下一个元素;
    • public boolean hasNext():如果仍有元素可以迭代,则返回true。
  • 注意:
    • 不要在使用迭代器进行迭代时,调用Collection的remove方法,否则会报异常。
    • 增强for循环(for each)底层也是迭代器。

10.2.2、List集合

1、List接口概述
  • List接口的元素有序、可重复、有索引。
2、List接口中常用方法
  • List作为Collection集合的子接口,不但继承了Collection接口中的全部方法,而且还增加了一些根据元素索引来操作集合的特有方法。
  • 添加元素:
    • void add(int index, E ele)
    • boolean addAll(int index, Collection<? extends E> eles)
  • 获取元素:
    • E get(int index)
  • 获取元素索引:
    • int indexOf(Object obj)
    • int lastIndexOf(Object obj)
  • 删除和替换元素:
    • E remove(int index)
    • E set(int index, E ele)
3、List接口的实现类
  • ArrayList:
    • 底层使用可变长度的Object类型数组实现;
    • 从JDK1.8开始构造方法不会为保存元素的数组初始化长度
    • 从JDK1.8开始第一次调用添加方法时,将初始化保存元素的数组,初始化长度为10;
    • 当元素已满时,数组需要扩容,默认扩容为1.5倍。
    • ArrayList遍历查询效率较高,增加删除效率较低。
  • LinkedList:
    • 底层使用双向链表实现;
    • 频繁存取效率高,遍历查询效率低。
  • Vector:动态数组
  • Stack:栈
4、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()

10.2.3、Set集合

1、Set概述
  • Set接口是Collection的子接口,set接口没有提供额外的方法;
  • Set 集合不允许包含相同的元素;
  • Set的常用实现类有:HashSet、TreeSet、LinkedHashSet;
  • Set集合支持的遍历方式和Collection集合一样:foreach和Iterator。
2、HashSet
  • HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类;
  • java.util.HashSet底层的实现其实是一个java.util.HashMap支持;
  • HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能;
  • HashSet 集合判断两个元素相等的标准: hashCode() 方法比较相等,equals() 方法返回值也相等。因此,存储到HashSet的元素要重写hashCode和equals方法。
3、LinkedHashSet
  • LinkedHashSet是HashSet的子类,它在HashSet的基础上,在结点中增加两个属性before和after维护了结点的前后添加顺序;
  • 它是链表和哈希表组合的一个数据存储结构;
  • LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。
4、TreeSet
  • 底层结构:里面维护了一个TreeMap,都是基于红黑树实现的;
  • 不允许重复;
  • 实现排序:
    • 自然排序
      • 如果使用的是自然排序,则通过调用实现的compareTo方法;
      • 让待添加的元素类型实现Comparable接口,并重写compareTo方法;
    • 定制排序
      • 如果使用的是定制排序,则通过调用比较器的compare方法;
      • 创建Set对象时,指定Comparator比较器接口,并实现compare方法。

10.2.4、Collections工具类

		List list = new ArrayList();
        list.add("罗老师");
        list.add("马老师");

        System.out.println(list);

        // 将多个元素一次性添加到一个集合中
        Collections.addAll(list, "老王", "老张");

        System.out.println(list);

        // 反转集合元素
        Collections.reverse(list);
        System.out.println(list);

        // 随机排列集合中的元素
        Collections.shuffle(list);
        System.out.println(list);

        // 二分查找的方式在List集合中查找参数元素的索引
        int binarySearch = Collections.binarySearch(list, "马老师");
        System.out.println(binarySearch);

        // 交换两个索引的位置
        Collections.swap(list,3,2);
        System.out.println(list);

        // 找出集合中的最大元素
        Comparable max = Collections.max(list);
        System.out.println(max);

        // 排序
        Collections.sort(list);
        System.out.println(list);

        // 返回参数集合中参数元素出现的次数
        int frequency = Collections.frequency(list,"马老师");
        System.out.println(frequency);

10.3、Map

10.3.1、Map常用方法

1、添加
  • V put(K key,V value)
  • void putAll(Map<? extends K,? extends V> m)
2、删除
  • void clear()
  • V remove(Object key)
3、查询
  • V get(Object key)
  • boolean containsKey(Object key)
  • boolean containsValue(Object value)
  • boolean isEmpty()
  • int size()
4、元视图操作
  • Set keySet()
  • Collection values()
  • Set<Map.Entry<K,V>> entrySet()
5、遍历
  • 分开遍历:
    • 单独遍历所有key
    • 单独遍历所有value
  • 成对遍历:
    • 通过Map.Entry

10.3.2、HashMap

1、概述
  • HashMap是Map接口使用频率最高的实现类;
  • 允许使用null键和null值,与HashSet一样,不保证映射的顺序;
  • 所有的key构成的集合时Set:无序的、不可重复的。所以,key在的类要重写:equals()和hashCode();
  • 所有的value构成的集合时Collection:无序的、可以重复。所以,value所在的类要重写:equals();
  • 一个key-value构成一个entry;
  • 所有的entry构成的集合是Set:无序的、不可重复的;
  • HashMap 判断两个 key 相等的标准是:两个 key 通过 equals() 方法返回 true,hashCode 值也相等。
  • HashMap 判断两个 value相等的标准是:两个 value 通过 equals() 方法返回 true。
2、存储结构(JDK1.8)
  • HashMap的内部存储结构其实是数组+链表+树的结合。当实例化一个HashMap时,会初始化initialCapacity和loadFactor,在put第一对映射关系时,系统会创建一个长度为initialCapacityNode数组,这个长度在哈希表中被称为容量(Capacity),在这个数组中可以存放元素的位置我们称之为“桶”(bucket),每个bucket都有自己的索引,系统可以根据索引快速的查找bucket中的元素。
  • 每个bucket中存储一个元素,即一个Node对象,但每一个Node对象可以带一个引用变量next,用于指向下一个元素,因此,在一个桶中,就有可能生成一个Node链。也可能是一个一个TreeNode对象,每一个TreeNode对象可以有两个叶子结点left和right,因此,在一个桶中,就有可能生成一个TreeNode树。而新添加的元素作为链表的last,或树的叶子结点。
  • 当HashMap中的元素个数超过数组大小(数组总大小length,不是数组中个数size)loadFactor 时 , 就会进行数组扩容 , loadFactor 的默认值(DEFAULT_LOAD_FACTOR)为0.75,这是一个折中的取值。也就是说,默认情况下,数组大小(DEFAULT_INITIAL_CAPACITY)为16,那么当HashMap中元素个数超过160.75=12(这个值就是代码中的threshold值,也叫做临界值)的时候,就把数组的大小扩展为 2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知HashMap中元素的个数,那么预设元素的个数能够有效的提高HashMap的性能。
  • 当HashMap中的其中一个链的对象个数如果达到了8个,此时如果capacity没有达到64,那么HashMap会先扩容解决,如果已经达到了64,那么这个链会变成树,结点类型由Node变成TreeNode类型。当然,如果当映射关系被移除后,下次resize方法时判断树的结点个数低于6个,也会把树再转为链表。
3、源码中的重要常量
  • DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16;
  • MAXIMUM_CAPACITY : HashMap的最大支持容量,2^30;
  • DEFAULT_LOAD_FACTOR:HashMap的默认加载因子;
  • TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树;
  • UNTREEIFY_THRESHOLD:Bucket中红黑树存储的Node小于该默认值,转化为链表;
  • MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量。(当桶中Node的数量大到需要变红黑树时,若hash表容量小MIN_TREEIFY_CAPACITY时,此时应执行resize扩容操作这个MIN_TREEIFY_CAPACITY的值至少是TREEIFY_THRESHOLD的4倍。)
  • table:存储元素的数组,总是2的n次幂;
  • entrySet:存储具体元素的集;
  • size:HashMap中存储的键值对的数量;
  • modCount:HashMap扩容和结构改变的次数;
  • threshold:扩容的临界值,=容量*填充因子;
  • loadFactor:填充因子;

10.3.3、Hashtable

  • HashMap和Hashtable都是哈希表。
  • HashMap和Hashtable判断两个 key 相等的标准是:两个 key 的hashCode 值相等,并且 equals() 方法也返回 true。因此,为了成功地在哈希表中存储和获取对象,用作键的对象必须实现 hashCode 方法和 equals 方法。
  • Hashtable是线程安全的,任何非 null 对象都可以用作键或值。
  • HashMap是线程不安全的,并允许使用 null 值和 null 键。

10.3.4、LinkedHashMap

LinkedHashMap 是 HashMap 的子类。此实现与 HashMap 的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。

10.3.5、TreeMap

基于红黑树(Red-Black tree)的 NavigableMap 实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。

10.3.6、Properties

  • Properties 类是 Hashtable 的子类,Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
  • 存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值