首页 > 其他分享 >集合、Collection 接口、List接口

集合、Collection 接口、List接口

时间:2023-07-05 19:34:26浏览次数:38  
标签:iterator int ArrayList elementData List Collection 接口

集合、Collection 接口、List接口

集合的理解和好处

前面,我们保存多个数据可以使用数组,但数组有不足的地方

  • 数组

    1. 数组的长度创建时必须指定,而且一定指定,不能修改

    2. 保存的必须为同一类型的元素

    3. 使用数组进行增加/删除的代码比较麻烦

      Person[] pers = new Person[1];
      pers[0] = new Person();
      
      // 增添新的Person对象
      Person[] pers2 = new Person[pers.length + 1];
      for (int i = 0; i < pers.length; i++) {
          pers2[i] = pers[i];
      }
      pers2[pers2.length - 1] = new Person();
      
  • 集合

    1. 可以动态保存任意多个对象,使用比较方便
    2. 提供了一系列方便操作对象的方法:add、remove、set、get等
    3. 使用集合添加、删除新元素的代码简洁明了

集合框架体系

Java集合类很多,主要分为两类:

单列集合(Collection)

Collection 接口有两个重要的子接口 List 和 Set,它们的子类都是单列集合。

image

双列集合(Map)

存放的一个元素包含两个值 key 和 value

image

Collection 接口和常用方法

Collection 接口实现类特点

public interface Collection<E> extends Iterable<E>
  1. Collection 实现子类可以存放对各元素,每个元素可以是Object
  2. 有些Collection的实现类,可以存放重复的元素,有些不可以
  3. Collection的实现类,有些是有序的(List),有些不是有序的(Set)
  4. Collection接口没有直接的实现子类,是通过它的子接口 Set 和 List 来实现的

Collection 接口的常用方法

boolean	add(E e)
boolean	addAll(Collection<? extends E> c)
void	clear()
boolean	contains(Object o)
boolean	containsAll(Collection<?> c)
boolean	isEmpty()
Iterator<E>	iterator()
boolean	remove(Object o)
boolean	removeAll(Collection<?> c)
int	size()
Object[]	toArray()
<T> T[]	toArray(T[] a)

Collection 接口遍历元素

public interface Iterator<E>

image

boolean	hasNext() //用于判断集合中是否还有下一个元素可以访问。
E	next() 	//返回迭代器的下一个元素,并将迭代器的指针移到下一个位置。
default void	remove() //从集合中删除迭代器最后访问的元素(可选操作)
  1. Iterator 对象称为迭代器,主要用于遍历 Collection 集合中的元素

  2. 所有实现了 Collection 接口的集合类都有一个 iterator() 方法,用以返回一个是实现了 Iterator 接口的对象,即可以返回一个迭代器

  3. Iterator 用于遍历集合,本身不存放对象

    注意:在调用 iterator.next() 方法之前必须要调用 iterator.hasNext() 进行检测。若不调用,且下一条记录无效,直接调用 it.next() 会抛出 NoSuchElementException 异常。

    // 1. 先得到 col 对应的迭代器
    // 2. 使用while循环遍历
     Iterator iterator = col.iterator();
    // 快速生成 while, idea 快捷键 itit
    while (iterator.hasNext()) {
        Object obj = iterator.next();
        System.out.println(obj);
    }
    // 快捷键提示 ctrl + j
    // 3.当退出 while 或,这是iterator 指向最后的元素
    //          iterator.next(); // SuchElementException
    // 如果希望再次遍历,需要重置迭代器
    iterator = col.iterator();
    
    
    // Collection 接口遍历对象2 -- for 循环增强, 底层依然是迭代器,快捷键 I
    for (Object o : col) {
        System.out.println("book=" + o);
    }
    
    

List 接口和常用方法

List 接口基本介绍

List 接口是 Collection 接口的子接口

  1. List 集合类中元素有序(即添加顺序和取出顺序一致,并且可以重复)

  2. List 集合中的每个元素都有其对应的顺序索引,即支持索引

  3. JDK API 中 List 接口的实现类

image

List 接口的常用方法

// List 集合里添加了一些根据索引来操作集合元素的方法
void	add(int index, E element)
boolean	addAll(int index, Collection<? extends E> c)
E	get(int index)
int	indexOf(Object o)
int	lastIndexOf(Object o)
E	remove(int index)
E	set(int index, E element)
default void	sort(Comparator<? super E> c)
List<E>	subList(int fromIndex, int toIndex)

List 接口遍历方式(ArrayLIst,LInkedList, Vector)

// 方式一:使用iterator
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
    Object obj = iterator.next();
    System.out.println(obj);
}
// 方式二:使用增强for
 for (Object o : list) {
      System.out.println(o);
}
// 方式三:使用for循环
for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}

ArrayList 注意事项

  1. permits all elements,includeing null,ArrayList 可以加入null,并且可以加入多个

  2. ArrayList 是由数组来实现数据存储的

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

image

image

ArrayList 的底层操作机制源码分析

image

  1. ArrayList 中维护了一个Object 类型的数组 elementData transient Object[] elementData;
  2. 当创建 ArrayList 对象时,如果使用的时无参构造器,则初始 elementData 容量为0,第一次添加,扩容 elementData 为10,如需要再次扩容,则扩容为 elementData 为1.5 倍
  3. 如果使用的是指定大小的构造器,则初始 elementData 的容量为指定大小,如果需要扩容,则直接扩容 elementData 为1.5倍
// 使用无参构造器创建 ArrayList
ArrayList list = new ArrayList();
  • // 创建了一个空的 elementData 数组
    public ArrayList() {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    
  // 使用for 给list结合添加1-10数据
for (int i = 1; i <= 10; i++) {
    list.add(i);
}
  • // 执行 list.add
    // (1) 先确定是否需要扩容
    // (2) 然后再执行赋值
    public boolean add(E e) {
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            elementData[size++] = e;
            return true;
        }
    
    • // 该方法确定 minCapacity
      // (1) 第一次扩容为10
      private void ensureCapacityInternal(int minCapacity) { // 1
              ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
      }
      
      • // (1)modCount++ 记录集合被修改改的次数
        // (2)如果 elementData 的大小不够就 调用 grow() 扩容
        private void ensureExplicitCapacity(int minCapacity) {
                modCount++; // 记录集合被修改的次数
        
                // overflow-conscious code
                if (minCapacity - elementData.length > 0) // 10-1 > 0 true
                    grow(minCapacity); // 扩容为10
        }
        
        • private static int calculateCapacity(Object[] elementData, int minCapacity) {
                  if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // true
                      return Math.max(DEFAULT_CAPACITY, minCapacity); 
                      //DEFAULT_CAPACITY=10, minCapacity=1, return 10
                  }
                  return minCapacity;
           }
          
      • // 实现扩容
        // (1) 使用扩容机制来确定要扩容到多大
        // (2) 第一次 newCapacity = 10
        // (3) 第二次及其以后,按照1.5倍扩容
        // (4) 扩容使用 Arrays.copyOf()
        private void grow(int minCapacity) {
                // overflow-conscious code
                int oldCapacity = elementData.length; // 0
                int newCapacity = oldCapacity + (oldCapacity >> 1); // 1.5倍扩容
                if (newCapacity - minCapacity < 0) // 0 - 10 < 0, true
                    newCapacity = minCapacity; // 10
                if (newCapacity - MAX_ARRAY_SIZE > 0)
                    newCapacity = hugeCapacity(minCapacity);
                // minCapacity is usually close to size, so this is a win:
                elementData = Arrays.copyOf(elementData, newCapacity); // 数组拷贝
        }
        
        
// 使用有参构造器,指定初始容量
// 唯一同的是初始化的elementData 数组大小为参数指定大小
 public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

Vector的基本介绍

  1. Vector 类的定义说明

  2. image

    image

  3. Vector 底层也是一个对象数组,propected Object[] elementData

  4. Vector 是线程同步的,即线程安全,Vector类的操作方法带有 synchronized

  5. 在开发中,需要线程同步安全时,考虑使用Vector

Vector 和 ArrayList 的比较

底层结构 版本 线程安全、效率 扩容倍数
ArrayList 可变数组 jdk1.2 不安全,效率高 无参构造器,第一次10,第二次开始1.5倍,有参构造器指定大小,每次按照1.5倍扩容
Vector 可变数组 jdk1.0 安全,效率不高 无参构造器,默认是10,满后按照2倍扩容,如果使用参数构造器指定大小,则每次按2倍扩容

LinkedList 介绍

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

LinkedList 的底层操作机制

  1. LinkedList 底层维护了一个双向链表

  2. Linked中维护了两个属性 first 和 last 分别指向 首结点和尾结点

  3. 每个结点(Node 对象),里面又维护了 prev,next,item 三个属性,其中 prev 指向前一个结点,next 指向后一个结点。最终实现双向链表

  4. 所以 LinkedList的元素添加和删除,不是通过数组完成的,效率较高

    image

    image

    LinkedList的属性

image

// LinkedList 的静态内部类 Node 
private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
}

image

ArrayList 和 LinkedList的比较

底层结构 增删的效率 改查的效率
ArrayList 可变数组 较低,数组扩容 较高
LinkedList 双向链表 较高,通过链表追加 较低

如何选择 ArrayList 和 LinkedList:

  1. 如果改查的操作多,选择ArrayList
  2. 如果增删的操作多,选择LinkedList
  3. 一般来说,程序中80%以上都是查询,因此大部分情况下都会先择ArrayList
  4. 在一个项目中,根据业务灵活选择,可能一个模块使用ArrayList,另一个模块是LinkedList

标签:iterator,int,ArrayList,elementData,List,Collection,接口
From: https://www.cnblogs.com/ai135/p/17529608.html

相关文章

  • 用户列表查询接口
    1.UserController1:list的路径2:用户名(不是必须属性用required=false)3:电话号码(不是必须属性用required=false)4:分页参数(必填)5:每一页显示多少条(必填)6:定义一个条件构造器7:条件用户名(做一个非空判断)8:条件电话号码(做一个非空判断)9:new一个page对象10:......
  • IDEA:MAVEN:Result Maps collection does not contain value for com.itheima.mapper.
    尝试过很多方法:我的代码与视频的一致仍然不可行。可以发现是mapper文件的错误后发现自己的资源文件下的包创建方式不对,尽管打的target包里仍然存在代码,仍是错误的。之后更改resource文件下包的命名方式用“/”来命名即可。   ......
  • 延迟队列服务提供对外接口
    延迟队列微服务:redis:list-执行时间<=当前时间   zset-当前时间<执行时间<当前时间+5分钟添加任务:【以防任务数量过大在,一旦服务器挂掉,内存所有的数据都消失了,所以要做数据持久化】添加任务到数据库、符合条件的任务添加到redis【list,zset......
  • 软件测试 | 如何使用代理配置快速定位接口测试脚本问题?
    更多软件测试学习资料!!!在调试接口用例过程中,如果响应结果和预期结果不一致,则需要检查请求信息。通过代理获取自动化测试中的请求响应信息,对比与正常请求响应的区别,就能够更直观的排查请求错误,相当于编写代码时的debug功能。实战练习在自动化测试中,不论是Java版本还是Python版......
  • Revit开发之 IExportContext接口详细
    如果要将Revit模型输出为特定的格式,则需要利用revit的数据导出接口,在revit的二次开发中,给我们提供IExportContext接口。当前接口可用户模型轻量化导出、自定义格式导出等。编号 函数名称函数功能1Finish在导出过程的最后,处理完所有的实体后调用此防范2IsCanceled......
  • 基础语法-集合LinkedList
    以下情况使用ArrayList:频繁访问列表中的某一个元素。只需要在列表末尾进行添加和删除元素操作。以下情况使用LinkedList:你需要通过循环迭代来访问列表中的某些元素。需要频繁的在列表开头、中间、末尾等位置进行添加和删除元素操作。......
  • 模拟嵌入式边缘计算卡设计方案:367-XC7Z100 板卡 基于zynq XC7Z100 FMC接口通用计算平
    基于zynqXC7Z100FMC接口通用计算平台 一、板卡概述北京太速科技板卡由SoCXC7Z100-2FFG900I芯片来完成卡主控及数字信号处理,XC7Z100内部集成了两个ARMCortex-A9核和一个kintex7的FPGA,通过PL端FPGA扩展FMC、光纤、IO等接口,PS端ARM扩展网络、USB、RS232等接口......
  • 【Oracle】行转列的函数wm_concat,listagg,xmlagg,pivot以及动态行转列
    【Oracle】行转列的几种情况表的数据如下朴实无华的函数1.wm_concat使用格式:select分组字段,wm_concat(要转换的列名)from表名groupby分组字段实例:selectit.Code,wm_concat(it.inv)fromttt20230705itgroupbyit.Code2.listagg()withingroup()使用格式:......
  • 未来数据定时刷新——从zset中获取预设时间内的任务添加到list中
    未来数据定时刷新——实现步骤:定时任务/每分钟————》未来数据的keys————》按照分值查询zset,判断数据是否到期——到期》同步到Redis中的list 1、如何获取zset中所有的key?keys模糊匹配,future。效率低SCNA命令:SCAN命令是一个基于游标的迭代器,SCAN命令......
  • 怎么做接口自动化?一名功能测试的心路历程
    小帅是一名功能测试工程师,最近参与的项目接口异常复杂,发版非常频繁,每次回归测试都得很久,项目负责人决定为这个项目搭建接口自动化流程,提高测试效率。这份重任最后还是到了小帅头上,问题来了,要搭建自动化测试,首先得精通一门编程语言,作为一名功能测试小帅感觉头都要大了,自己也只会简......