1. List接口和常用方法

1.1 List接口基本介绍

1、返回集合长度

int size()

2、添加元素

void add(Object ele), void add(int index, Object ele)

3、添加多个元素

boolean addAll(int index, Collection eles)

4、获取指定index位置的元素

Object get(int index)

5、返回obj在集合中首次出现的位置

int indexOf(Object obj)

6、返回obj在集合中末次出现的位置

int lastIndexOf(Object obj)

7、移除指定index位置的元素,并返回此元素

Object remove(int index)

8、设置指定index位置的元素为ele,相当于替换,索引必须存在

Object set(int index, Object ele)

9、返回从fromIndex到toIndex位置的子集合,前闭后开

List subList(int fromIndex, int toIndex)

1.2 List接口的三种遍历方式

2. ArrayList

2.1 注意事项

2.2 ArrayList的底层操作机制源码分析(重点)

使用无参构造器

  • 可以看出elementData一开始是个空数组



  • 执行list.add(i)时,会先把int类型的i转化为Integer类型

  • 然后执行add方法,首先确认数组大小够不够,然后再对数组元素赋值

  • 如何确认数组大小够不够呢

    • 当数组为空时

      • 先设置数组需要的最小长度minCapacity为10
      • 然后判断数组需要的最小长度是否大于数组长度,此时一定大于,因为数组长度为0
      • 大于则扩容
    • 当数组不为空时
      • 先计算数组所需要的最小长度,即索引的位置+1,minCapacity=size+1
      • 然后计算当前数组的长度elementData.length
      • 判断数组所需的最小长度是否大于当前数组长度,大于则扩容(即当索引+1超出数组长度时,扩容)
    • 其中modCount用来记录集合被修改的次数



  • 如何扩容呢-调用grow函数

    • 当第一次扩容,即数组为空时,elementData.length=0

      • 通过位运算计算得到的newCapacity还是0,所以需要加个判断条件,给newCapacity赋值为minCapacity
      • 然后使用Arrays的copyOf方法进行数组扩容
    • 当不是第一次扩容时
      • 根据位运算在原来数组长度上扩大1.5倍得到,向下取整,newCapacity
      • 然后使用Arrays的copyOf方法进行数组扩容

使用有参构造器

  • 首先创建一个指定大小elementData数组

  • 其它流程在无参构造器中以出现,不再重复

总结

  • 关键是维护一个elementData数组,当new一个对象时,

    • 使用无参构造时,它为空数组
    • 使用有参构造时,它的长度为传入的参数值,并且给elementData new一个长度为参数大小的数组
  • 当使用add方法时,首先会计算容器所需要的最小容量是多少,即minCapacity
    • 如果是空数组,设置最小容量为10
    • 如果不是,最小容量就是索引位置+1(size+1)
  • 然后判断这个最小容量是否大于数组长度
    • 如果大于,就说明要扩容了
    • 如果小于,什么也不干
  • 扩容时,扩容大小使用位操作计算,当前容量+右移一位,(右移一位会小一半),所以扩大1.5倍
    • 但是当容量为0时,0右移一位还是0,所以加了一个判断,给这个容量直接赋值为10

关键是维护一个elementData数组,如果是无参构造,一开始将elementData数组初始化为空数组,当执行添加操作时,需要第一次扩容到10,后面按1.5倍扩容;如果是有参构造,一开始将elementData的大小初始化为参数值,之后每次扩容按1.5倍扩,扩容是创建一个新数组,然后调用一个本地方法将原来数组的值复制到新数组

3. Vector

3.1 基本介绍

3.2 Vector与ArrayList的比较

3.3 源码分析

  • 首先通过构造方法设置数组初始容量,并创建一个指定长度的数组

    • 无参构造器默认设置初始容量为10

    • 有参构造器根据指定数值设置容量,扩容增量默认为0
    • 还可以自己设置扩容增量
  • 然后对int类型自动装箱

  • 接着执行add方法

    • 首先确认当前的容量大小是否需要扩容



    • 如果需要扩容,且设置了扩容增量capacityIncrement的话,就扩容这个值的大小,如果没设置扩容增量,就扩容原来的两倍

  • 最后将数据添加到Vector集合中

3.4 总结

  • 如果是无参构造,直接默认创建一个初始容量为10的数组,之后每次需要扩容时,扩大两倍
  • 如果是有参构造,创建初始容量为指定值的数组,如果设置了扩容增量,之后每次扩容时,扩容后的大小等于当前容量+扩容增量,如果没设置扩容增量,则扩容两倍。

4. LinkedList

基本介绍



源码分析

add()函数

  • 首先通过无参构造方法初始化属性



  • 对int类型自动装箱后,执行add方法

  • 其中最关键的方法是linkLast方法

    • 当linkList中没有元素时

      • 首先创建临时节点,使用l记录last的位置
      • 然后创建新节点,让它的pre指向临时节点、next指向null
      • 更新双指针的位置,将last和first都指向该新节点
    • 当linkList中有元素时
      • 首先创建临时节点,使用l记录last的位置
      • 然后创建新节点,让它的pre指向临时节点、next指向null
      • 然后让临时节点的next指针指向新节点
      • 大概思路是更新新节点和原来最后一个节点之间的pre和next指针指向

remove()函数

  • 删除节点默认删除第一个节点



  1. 首先它直接调用了removeFirst()方法



  2. 真正删除第一个节点的方法是unLinkFirst()

  • 首先使用临时变量保存原来first指向的节点 的元素值和next指针
  • 清空原来first指向的节点 的元素值和next指针
  • 改变first指针指向临时变量保存的next指针(即原来第二个节点)
    • 但next可能为null(即原list只有一个节点的情况)

      • 此时将last指针也指向null
    • 当next不为null
      • 将next指针(即新的第一个节点)的prev指向null
  • 此时已实现first指向原第二个节点,如果第二个节点为null,first和last都指向null
  • 最后返回删除的节点的元素值

总结:

  • 新增节点:先用临时变量记录最后一个节点,然后创建一个新节点,将新节点连接到原来链表上(新节点的pre指针指向临时节点,next指针指向null,最后临时节点的next指针指向新节点),更新last的位置,如果原来为空,还要将first也指向这个节点
  • 删除节点:先用临时节点保存第一个节点,然后清空第一个节点next指针和元素值,将firs指向第二个节点,如果这个节点为空,将last也指向它;
  • 总结:先用临时变量保存需要处理的节点,然后再处理该节点,特殊情况是只有一个节点或没有节点的时候,此时两个指针都要移动。

5. List集合选择

  • ArrayList可以通过索引直接定位
  • linkedlist通过遍历查找

    注意:线程都是不安全的

    补充:

    Alt+7:查看当前类的所有方法

Set接口



  • 常用方法和遍历方式

  • 存放顺序和取出顺序不一致,但是取出顺序是固定的

  • set接口对象不能通过索引获取,它没有get方法

HashSet



  • 注意:是当一条链表的个数达到8个,同时table元素达到64个,才会树化
  • 当一条链表达到8个了,但是元素少数64个,table会扩容

  • 扩容时,不是数组里的元素达到阈值才扩容,而是所有元素数量(包括链表上的)达到阈值就会扩容

HashSet的底层就是HashMap,只是在HashSet里,value是存放的一个常量对象,平时的操作只用key

当添加元素时,

Map接口

Node实现了Entry接口,Entry接口里有getKey和getValue方法,然后EntrySet集合里存放着Node类型的对象(多态)

遍历方式

  • 第一组:先取出所有的key,通过key取出对应的value

  • 第二组:把所有的value取出
  • 第三组:通过EntrySet 来获取 k-v

小结

HashMap底层

HashMap扩容机制

源码

  1. 执行构造器 new HashMap()

  2. 执行put,调用hash方法
  3. 执行putVal
  4. 关于转成红黑树

HashTable









集合选择

List、Set与 Map的更多相关文章

  1. mapreduce中一个map多个输入路径

    package duogemap; import java.io.IOException; import java.util.ArrayList; import java.util.List; imp ...

  2. .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法

    .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法 0x00 为什么需要Map(MapWhen)扩展 如果业务逻辑比较简单的话,一条主管道就够了,确实用不到 ...

  3. Java基础Map接口+Collections工具类

    1.Map中我们主要讲两个接口 HashMap  与   LinkedHashMap (1)其中LinkedHashMap是有序的  怎么存怎么取出来 我们讲一下Map的增删改查功能: /* * Ma ...

  4. Java基础Map接口+Collections

    1.Map中我们主要讲两个接口 HashMap  与   LinkedHashMap (1)其中LinkedHashMap是有序的  怎么存怎么取出来 我们讲一下Map的增删改查功能: /* * Ma ...

  5. 多用多学之Java中的Set,List,Map

            很长时间以来一直代码中用的比较多的数据列表主要是List,而且都是ArrayList,感觉有这个玩意就够了.ArrayList是用于实现动态数组的包装工具类,这样写代码的时候就可以拉进 ...

  6. Java版本:识别Json字符串并分隔成Map集合

    前言: 最近又看了点Java的知识,于是想着把CYQ.Data V5迁移到Java版本. 过程发现坑很多,理论上看大部分很相似,实践上代码写起来发现大部分都要重新思考方案. 遇到的C#转Java的一些 ...

  7. MapReduce剖析笔记之八: Map输出数据的处理类MapOutputBuffer分析

    在上一节我们分析了Child子进程启动,处理Map.Reduce任务的主要过程,但对于一些细节没有分析,这一节主要对MapOutputBuffer这个关键类进行分析. MapOutputBuffer顾 ...

  8. MapReduce剖析笔记之七:Child子进程处理Map和Reduce任务的主要流程

    在上一节我们分析了TaskTracker如何对JobTracker分配过来的任务进行初始化,并创建各类JVM启动所需的信息,最终创建JVM的整个过程,本节我们继续来看,JVM启动后,执行的是Child ...

  9. MapReduce剖析笔记之五:Map与Reduce任务分配过程

    在上一节分析了TaskTracker和JobTracker之间通过周期的心跳消息获取任务分配结果的过程.中间留了一个问题,就是任务到底是怎么分配的.任务的分配自然是由JobTracker做出来的,具体 ...

  10. MapReduce剖析笔记之三:Job的Map/Reduce Task初始化

    上一节分析了Job由JobClient提交到JobTracker的流程,利用RPC机制,JobTracker接收到Job ID和Job所在HDFS的目录,够早了JobInProgress对象,丢入队列 ...

随机推荐

  1. 4.7 x64dbg 应用层的钩子扫描

    所谓的应用层钩子(Application-level hooks)是一种编程技术,它允许应用程序通过在特定事件发生时执行特定代码来自定义或扩展其行为.这些事件可以是用户交互,系统事件,或者其他应用程序 ...

  2. 根据模板动态生成word(三)使用poi-tl生成word

    @ 目录 一.前言 1.什么是poi-tl 2.官方信息 2.1 源码仓库 2.2 中文文档 2.3 开源协议 3.poi-tl的优势 3.1 poi-tl和其他模板引擎的对比 3.2 poi-tl ...

  3. Maven配置UTF8,JDK版本

    <!-- 局部jdk配置,pom.xml中 --> <build> <plugins> <plugin> <groupId>org.apac ...

  4. Redis Stack:基于Redis的搜索、文档、图形和时间序列功能

    基于Redis的搜索.文档.图和时间序列功能整合到一个扩展Redis Stack中,以使开发人员能够轻松构建实时应用程序. Redis Stack 于 3 月 23 日发布,由三个组件组成: Redi ...

  5. Blazor如何跟随“系统主题”?

    1. 前言 跟随系统主题已经是绝大多数App和网站的标配 但是如何在Blazor中跟随系统主题? 只找到Masa Blazor技术团队发的 MAUI + Masa Blazor 开发界面跟随系统主题切 ...

  6. 【技术积累】Vue中的核心概念【四】

    Vue的生命周期 Vue中的生命周期是指组件从创建到销毁的整个过程中,会触发一系列的钩子函数 Vue2中的生命周期 Vue2中的生命周期钩子函数是在组件的不同阶段执行的特定函数.这些钩子函数允许开发者 ...

  7. 【技术实战】Vue技术实战【三】

    需求实战一 效果展示 代码展示 <template> <div style="display: flex;"> <div style="di ...

  8. CSS: 绝对定位fixed

    属性介绍 元素会被移出正常文档流,并不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置.元素的位置在屏幕滚动时不会改变.打印时,元素会出现在的每页的固定位置.fi ...

  9. servlet系列:简介和基本使用以及工作流程

    目录 一.简介 二.Servlet实现 三.基本使用 1.引入pom依赖 2.实现Servlet规范,重写service方法 3.配置web.xml 4.配置Tomcat 6.运行 四.Servlet ...

  10. Vue 框架下提升加载速度的一些实战经验分享

    现在前端的框架有很多,甚至两只手已经数不过来,当然也完全没必要全部都学,还是应该深入的学习一两个被广泛使用的就好.其实我和大部分同学的想法一致,认为最值得我们深究的还是主流的 Vue 和 React. ...