Java之集合——详细概括和ArrayList的底层源码解析

目录

一、集合的家族谱

1.List

2. Set

3.Map

4.Collection接口的方法(List、Set实现类通用)

5.Map接口实现方法(Map实现类通用)

二、ArrayList底层原码的详解

1.前菜

 2.底层原码解析

示例代码

(1)概况

​编辑                         

(2)源码用到的常量和变量

(3)分步源码详解

A.    ArrayList list = new ArrayList<>();

B.第一层for循环   list.add(0);

C.剩下九层循环list.add(i);1~9

D. list.add(10);

 3.总结


 

前言

前面说了java的基本类型和引用类型,有说到数组的相关内容和其内存图,但是数组的用处非常局限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。获取数据中实际元素的个数的需求,数组没有现成的属性或方法可用。数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足。

于是这次要说到以后要经常用到的java容器———集合。


提示:以下是本篇文章正文内容,下面案例可供参考

一、集合的家族谱

Java的容器主要分为2个大类,即Collection和Map。Collection代表着集合,类似数组,只保存一个数字。而Map则是映射,保留键值对两个值。
List 、Queue、 Set、 Map 这四个的区别。

A.List(对付顺序的好帮手): 存储的元素是有序的、可重复的。
B.Set (注重独一无二的性质):存储的元素是无序的、不可重复的。
C.Queue (实现排队功能的叫号机):按特定的排队规则来确定先后顺序,存储的元素是有序的、可重复的。
D.Map (用 key 来搜索的专家) :使用键值对(key-value)存储,类似于数学上的函数 y=f(x),“x” 代表 key,“y” 代表 value,key 是无序的、不可重复的,value 是无序的、可重复的,每个键最多映射到一个值。 

1.List

2. Set

3.Map

4.Collection接口的方法(List、Set实现类通用)

List接口和Set接口下的实现类都实现了Collection接口,所以类的方法用法命名都差不多,更多细节可查看API文档 Java 8 中文版 - 在线API手册 - 码工具 (matools.com)

5.Map接口实现方法(Map实现类通用)

 更多细节可查看API文档 Java 8 中文版 - 在线API手册 - 码工具 (matools.com)

二、ArrayList底层原码的详解

1.前菜

在说ArrayList底层原码之前要说两个重要的点:

A.集合里面装的都是引用类型的数据,所以即使是add()或者put()方法装入8种基本类型数据之前,基本数据会自动装箱,变成包装类型(引用类型),就可以放入到集合中。

B.集合有一个好兄弟,叫做泛型(<  Integer >),因为集合可以添加任意引用类型的数据,在现实的业务中不够严谨,所以需要好兄弟泛型来限制可以加入到集合的数据的数据类型。泛型里面也是不允许出现基本类型的,都是引用类型。

没加泛型前:

加入泛型后 


 2.底层原码解析

示例代码

public class ArrayListType {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add(i);//第一次循环第一次添加数据时,集合扩容到默认值10
        }
        list.add(10);//添加第11个元素时不够装了,集合扩容1.5倍到15
        System.out.println(list);
    }
}

(1)概况

                         

(2)源码用到的常量和变量

elementDate :   就是底层代表集合的一个对象数组  Object[ ]  elementData  操作集合就是操作这个对象数组

DEFAULTCAPACITY_EMPTY_ELEMENTDATA:就是一个空的对象数组,在new 一个空的ArrayList时,将这个值赋给elementDate,还有扩容的时候判断是否为空数组,是否走默认扩容

DEFAULT_CAPACITY:就是空的ArrayList在添加第一个数据的时候,先扩容到默认初始容量为10 ,要用到这个数值。

size:集合中元素的个数。 

modCount:记录操作集合的次数。

minCapacity:先提前加入一个元素后集合元素的个数。(size+1)

(3)分步源码详解

public class ArrayListType {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add(i);//第一次循环第一次添加数据时,集合扩容到默认值10
        }
        list.add(10);//添加第11个元素时不够装了,集合扩容1.5倍到15
        System.out.println(list);
    }
}
A.    ArrayList<Integer> list = new ArrayList<>();

这一步创建一个空的数组。debug进去

 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 这个空的对象数组赋值给集合的本体elementDate

B.第一层for循环   list.add(0);

将0这个基本类型自动装箱。(Integer.valueof(0) )

要加入的数据 e ,   集合数组 elementData,  集合包含数据的个数 size 传入内层add 方法

 s就是传入的size , s == elementDate.length 代表集合包含数据的个数等于集合的最大容量了,需要扩容了。进入grow()方法返回一个扩容后的对象数组。

size+1 得到 minCapacity(当作加入数据后集合数据的个数)传入内层grow()

将minCapacity参数引入new Capacity()方法,返回一个整形数据,代表扩容后集合的容量。

注意:new Capacity()方法要么返回默认容量大小10,或扩容后的1.5倍原容量。

这个方法中先得到oldCapacity老集合的容量,以倍数扩容的newCapacity新容量,进入if模块,发现新容量newCapacity小于加入数据的集合数据的个数minCapacity,返回默认容量DEFAULT_CAPACITY。

通过Arrays数组工具类的copyOf()方法,复制原数组到一个扩大到长度为10的一个副本数组,最后将副本数组赋值给elementData,替代原数组。

将得到扩容后的数组返回,将数据插入数组,集合数据个数size+1。

 

数据添加成功,外出add()返回ture。 

C.剩下九层循环list.add(i);1~9

除了不用进入到扩容的方法两层grow()和new capacity(minCapacity),步骤都跟第一层一样。

D. list.add(10);

这一步前面已经添加了10个数据了,达到了集合容量10,要进行扩容。

这一步与步骤B不同的是new capacity(minCapacity)方法不一样,其他的步骤都一样。

不一样的步骤如下:

新容量newCapacity大于添加数据后集合数据的个数,走倍数扩容。

 3.总结

 

 

 

 

 

 

  • 12
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值