• 第十四章 集合(集合框架体系、List)


    一、集合框架体系

    (1)可以动态保存任意多个对象
    (2)提供了一系列方便的操作对象的方法:add、remove、set、get 等

    集合框架体系:

    二、Collection

    1. Collection 接口常用方法

    (1)add:添加单个元素

    (2)remove:删除指定元素

    (3)contains:查找元素是否存在

    (4)size:获取元素个数

    (5)isEmpty:判断是否为空

    (6)clear:清空

    (7)addAll:添加多个元素

    (8)containsAIl:查找多个元素是否都存在

    (9)removeAll:删除多个元素

    2. Collection 接口遍历元素方式1,使用 Iterator(迭代器)

    (1)Iterator 对象称为迭代器,主要用于遍历 Collection 集合中的元素。
    (2)所有实现了 Collection 接口 的集合类都有一个 iterator() 方法,用以返口一个实现了Iterator 接口的对象,即可以返回一个迭代器。
    (3)Iterator 仅用于遍历集合,lterator 本身并不存放对象。

    1. public class Test {
    2. public static void main(String[] args) {
    3. ArrayList list = new ArrayList<>();
    4. list.add(1);
    5. list.add(2);
    6. list.add(3);
    7. // list.iterator() 重置迭代器,可重复
    8. Iterator iterator = list.iterator();
    9. while (iterator.hasNext()) {
    10. Integer next = iterator.next();
    11. System.out.println(next);
    12. }
    13. }
    14. }

    3. Collection 接口遍历元素方式2,增强 for 循环

    增强 for 循环,可以代替 iterator 迭代器,特点:增强 for 本质就是迭代器。只能用于遍历集合或数组。

    1. public class Test {
    2. public static void main(String[] args) {
    3. ArrayList list = new ArrayList<>();
    4. list.add(1);
    5. list.add(2);
    6. list.add(3);
    7. for (Integer e : list) {
    8. System.out.println(e);
    9. }
    10. }
    11. }

    三、List

    1. List 接口基本介绍

    (1)List 接口是 Collection 接口的子接口

    (2)List 集合类中元素有序(即添加顺序和取出顺序一致)、且可重复

    (3)List 集合中的每个元素都有其对应的顺序索引,即支持索引。

    (4)List 容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素

    2. List 集合里添加了一些根据索引来操作集合元素的方法

    (1)void add (int index, Object ele):在 index 位置插入 ele 元素

    (2)boolean addAll (int index, Collection eles):从 index 位置开始将 eles 中的所有元素添加进来

    (3)Object get (int index):获取指定 index 位置的元素

    (4)int indexOf (Object obj):返回 obj 在集合中首次出现的位置

    (5)int lastlndexOf (Object obj):返回 obj 在当前集合中末次出现的位置

    (6)Object remove (int index):移除指定 index 位置的元素,并返回此元素

    (7)Object set (int index, Object ele):设置指定 index 位置的元素为 ele,相当于是替换

    (8)List subList (int fromlndex,int tolndex):返回从 fromlndex 到(tolndex -1)位置的子集合

    1. public class Test {
    2. public static void main(String[] args) {
    3. List list = new ArrayList<>();
    4. list.add("乔峰");
    5. list.add("段誉");
    6. list.add(1, "虚竹");
    7. list.add("Tom");
    8. System.out.println(list); // [乔峰, 虚竹, 段誉, Tom]
    9. List list2 = new ArrayList<>();
    10. list2.add("Jack");
    11. list2.add("Tom");
    12. list.addAll(1, list2);
    13. System.out.println(list); // [乔峰, Jack, Tom, 虚竹, 段誉, Tom]
    14. System.out.println(list.get(1)); // Jack
    15. System.out.println(list.indexOf("Tom")); // 2
    16. System.out.println(list.lastIndexOf("Tom")); // 5
    17. list.remove(5);
    18. System.out.println(list); // [乔峰, Jack, Tom, 虚竹, 段誉]
    19. list.set(2, "Mike");
    20. System.out.println(list); // [乔峰, Jack, Mike, 虚竹, 段誉]
    21. System.out.println(list.subList(0, 2)); // [乔峰, Jack]
    22. }
    23. }

    四、ArrayList(P509) 

    1. ArrayList 的注意事项

    (1)ArrayList 可以加入 null,并且多个。

    (2)ArrayList 是由数组来实现数据存储的。

    (3)ArrayList 基本等同于 Vector。ArrayList 是线程不安全(执行效率高),在多线程情况下,不建议使用ArrayList。

    2. ArrayList 的底层操作机制源码分析(P510)

    (1)ArrayList 中维护了一个 Object 类型的数组,transient Object[] elementData【transient  表示该属性不会被序列化】

    (2)当创建 ArrayList  对象时,如果使用的是无参构造器,则初始 elementData 容量为 0。

    第一次添加,则扩容 elementData 为 10。如果需要再次扩容的话,则扩容 elementData 为1.5 倍

    (3)如果使用的是指定大小的构造器,则初始 elementData 容量为指定大小,如果需要扩容,则直接扩容 elementData 为1.5倍。

    1. public class ArrayList_ {
    2. transient Object[] elementData;
    3. private int size;
    4. protected transient int modCount = 0;
    5. private static final int DEFAULT_CAPACITY = 10;
    6. private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    7. // 无参构造
    8. public ArrayList_() {
    9. // 创建一个空的数组
    10. this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    11. }
    12. public ArrayList_(int initialCapacity) {
    13. if (initialCapacity > 0) {
    14. this.elementData = new Object[initialCapacity];
    15. }
    16. }
    17. public boolean add(E e) {
    18. ensureCapacityInternal(size + 1); // Increments modCount!!
    19. // 在 elementData[size] 赋值,并且size++
    20. elementData[size++] = e;
    21. return true;
    22. }
    23. private void ensureCapacityInternal(int minCapacity) {
    24. ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    25. }
    26. private void ensureExplicitCapacity(int minCapacity) {
    27. // 操作次数
    28. modCount++;
    29. // overflow-conscious code
    30. // 判断是否扩容,如果elementData数组大小不够就扩容
    31. if (minCapacity - elementData.length > 0){
    32. grow(minCapacity);
    33. }
    34. }
    35. private static int calculateCapacity(Object[] elementData, int minCapacity) {
    36. if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
    37. return Math.max(DEFAULT_CAPACITY, minCapacity);
    38. }
    39. return minCapacity;
    40. }
    41. private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    42. // 扩容方法
    43. private void grow(int minCapacity) {
    44. // overflow-conscious code
    45. int oldCapacity = elementData.length;
    46. // 扩容为1.5倍
    47. int newCapacity = oldCapacity + (oldCapacity >> 1);
    48. if (newCapacity - minCapacity < 0){
    49. newCapacity = minCapacity;
    50. }
    51. // 防止超过最大值2147483639
    52. if (newCapacity - MAX_ARRAY_SIZE > 0){
    53. newCapacity = hugeCapacity(minCapacity);
    54. }
    55. // minCapacity is usually close to size, so this is a win:
    56. // Arrays.copyOf 可以保留原先的数据,并扩容
    57. elementData = Arrays.copyOf(elementData, newCapacity);
    58. }
    59. private static int hugeCapacity(int minCapacity) {
    60. if (minCapacity < 0){
    61. // overflow
    62. throw new OutOfMemoryError();
    63. }
    64. return (minCapacity > MAX_ARRAY_SIZE) ?
    65. Integer.MAX_VALUE :
    66. MAX_ARRAY_SIZE;
    67. }
    68. }

    五、Vector(P513)

    1. Vector 的基本介绍

    (1)Vector 类的定义说明

    1. public class Vector
    2. extends AbstractList
    3. implements List, RandomAccess, Cloneable, java.io.Serializable

    (2)Vector 底层也是一个对象数组 protected Object[] elementData;

    (3)Vector 是线程同步的,即线程安全,Vector 类的操作方法带有 synchronized。

    (4)在开发中,需要线程同步安全时,考虑使用 Vector。

    2. Vector 的底层操作机制源码分析

    Vector 扩容源码类似于 ArrayList

    1. public class Vector_ {
    2. protected Object[] elementData;
    3. protected int capacityIncrement;
    4. protected transient int modCount = 0;
    5. protected int elementCount;
    6. public Vector_() {
    7. this(10);
    8. }
    9. public Vector_(int initialCapacity) {
    10. this(initialCapacity, 0);
    11. }
    12. public Vector_(int initialCapacity, int capacityIncrement) {
    13. super();
    14. if (initialCapacity < 0){
    15. throw new IllegalArgumentException("Illegal Capacity: "+
    16. initialCapacity);
    17. }
    18. // 初始化数组
    19. this.elementData = new Object[initialCapacity];
    20. this.capacityIncrement = capacityIncrement;
    21. }
    22. public synchronized boolean add(E e) {
    23. modCount++;
    24. ensureCapacityHelper(elementCount + 1);
    25. elementData[elementCount++] = e;
    26. return true;
    27. }
    28. private void ensureCapacityHelper(int minCapacity) {
    29. // overflow-conscious code
    30. // 判断是否扩容
    31. if (minCapacity - elementData.length > 0){
    32. grow(minCapacity);
    33. }
    34. }
    35. private void grow(int minCapacity) {
    36. // overflow-conscious code
    37. int oldCapacity = elementData.length;
    38. // newCapacity = oldCapacity + oldCapacity
    39. int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
    40. capacityIncrement : oldCapacity);
    41. if (newCapacity - minCapacity < 0){
    42. newCapacity = minCapacity;
    43. }
    44. elementData = Arrays.copyOf(elementData, newCapacity);
    45. }
    46. }

    六、LinkedList(P515)

    1. LinkedList 说明

    (1)LinkedList 底层实现了双向链表双端队列特点。
    (2)可以添加任意元素(元素可以重复),包括 null。
    (3)线程不安全,没有实现同步。

    2. LinkedList 的底层操作机制

    (1)LinkedList 底层维护了一个双向链表。
    (2)LinkedList 中维护了两个属性 first 和 last 分别指向首节点和尾节点。
    (3)每个节点(Node对象),里面又维护了 prev 、next 、item 三个属性,其中通过 prev 指向前一个,通过 next 指向后一个节点。最终实现双向链表。

    (4)所以 LinkedList 的元素的添加和删除,不是通过数组完成的,相对来说效率较高。

    3. LinkedList 源码解读(P516)

    1. public class LinkedList_ {
    2. transient int size = 0;
    3. protected transient int modCount = 0;
    4. transient Node first;
    5. transient Node last;
    6. private static class Node {
    7. E item; // 存放数据
    8. Node next;
    9. Node prev;
    10. Node(Node prev, E element, Node next) {
    11. this.item = element;
    12. this.next = next;
    13. this.prev = prev;
    14. }
    15. }
    16. public boolean add(E e) {
    17. linkLast(e);
    18. return true;
    19. }
    20. void linkLast(E e) {
    21. final Node l = last;
    22. final Node newNode = new Node<>(l, e, null);
    23. last = newNode;
    24. if (l == null) {
    25. first = newNode;
    26. } else {
    27. l.next = newNode;
    28. }
    29. size++;
    30. modCount++;
    31. }
    32. public E remove() {
    33. return removeFirst();
    34. }
    35. public E removeFirst() {
    36. final Node f = first;
    37. if (f == null) {
    38. throw new NoSuchElementException();
    39. }
    40. return unlinkFirst(f);
    41. }
    42. private E unlinkFirst(Node f) {
    43. // assert f == first && f != null;
    44. final E element = f.item;
    45. final Node next = f.next;
    46. f.item = null;
    47. f.next = null; // help GC
    48. first = next;
    49. if (next == null) {
    50. last = null;
    51. } else {
    52. next.prev = null;
    53. }
    54. size--;
    55. modCount++;
    56. return element;
    57. }
    58. }

    七、ArrayList 和 LinkedList 比较(P517)

    (1)如果我们改查的操作多,选择 ArrayList。
    (2)如果我们增删的操作多,选择 LinkedList。
    (3)一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择 ArrayList。

  • 相关阅读:
    conan入门(二十九):对阿里mnn进行Conan封装塈conans.CMake和conan.tools.cmake.CMake的区别
    AI算法助力室内家具布局
    机器学习2--matplotlib绘图包
    [Spring Framework]AOP经典案例、AOP总结
    Java通过Lettuce访问Redis主从,哨兵,集群
    如何计算多分组交互pp值
    菲律宾外汇储备降至两年来的最低水平
    《Effective Objective-C 2.0》读书笔记——对象、消息、运行期
    vue清除动态路由
    基于Redis实现分布式锁(执行流程)
  • 原文地址:https://blog.csdn.net/yirenyuan/article/details/130882284