首先我们要明白java中的集合Collection,List,ArrayList之间的关系:

  ArrayList是具体的实现类,实现了List接口

  List是接口,继承了Collection接口

  List继承了Collection接口   但是List是可以重复的并且有序的集合 Collection是不可重复且无序的

这里我们先讲一下List集合:

List接口不能被构造 也就是我们说的不能创建实例对象 但是我们可以像下面那样为List接口创建一个指向自己的对象引用 而ArrayList实现类的实例对象就在这充当了这个指向List接口的对象引用 这也是多态的一种:

  1. List<String> list = new ArrayList<String>();

那么现在问题来了

为什么要用 List list = new ArrayList()  而不用 ArrayList alist = new ArrayList()呢?

问题就在于List接口有多个实现类  现在你用的是ArrayList  也许哪一天你需要换成其它的实现类 如 LinkedList或者Vector等等 这时你只要改变这一行就行了:

  List list = new LinkedList();   其它使用了list地方的代码根本不需要改动

假设你开始用ArrayList alist = new ArrayList()  那需要改的地方就很多了  特别是如果你使用了ArrayList实现类特有的方法和属性。

  这样的好处也是为了代码的可维护性 可复用性 可扩展性以及灵活性 再者就是这符合了里氏代换原则和开闭原则

言归正传 我们下面说一下 集合的长度为什么是不固定的

我们知道集合的底层其实也是用数组实现的 那么为什么定义集合的时候 是不需要给出size的 而数组在定义的时候就需要给出长度?

首先我们分析一下ArrayList的无参构造方法:

  1. /**
  2. * Constructs an empty list with an initial capacity of ten.
  3. */
  4. public ArrayList() {
  5. super();
  6. this.elementData = EMPTY_ELEMENTDATA;
  7. }
  8.  
  9. /**
  10. * Default initial capacity.
  11. */
  12. private static final int DEFAULT_CAPACITY = 10;
  13.  
  14. /**
  15. * Shared empty array instance used for empty instances.
  16. */
  17. private static final Object[] EMPTY_ELEMENTDATA = {};
  18.  
  19. /**
  20. * The array buffer into which the elements of the ArrayList are stored.
  21. * The capacity of the ArrayList is the length of this array buffer. Any
  22. * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to
  23. * DEFAULT_CAPACITY when the first element is added.
  24. */
  25. private transient Object[] elementData;

我们发现无参的构造方法里面 this.elementData = EMPTY_ELEMENTDATA;  相当于给集合了一个空的数组 而且上面代码紫色部分说在第一次给集合添加元素的时候 会把 DEFAULT_CAPACITY 也就是10设置成数组长度

那么我们通过ArrayList中的add方法看一看是否是这样子:

  1. /**
  2. * The size of the ArrayList (the number of elements it contains).
  3. *
  4. * @serial
  5. */
  6. private int size;
  7.  
  8. /**
  9. * Appends the specified element to the end of this list.
  10. *
  11. * @param e element to be appended to this list
  12. * @return <tt>true</tt> (as specified by {@link Collection#add})
  13. */
  14. public boolean add(E e) {
  15. ensureCapacityInternal(size + 1); // Increments modCount!!
  16. elementData[size++] = e;
  17. return true;
  18. }
  19.  
  20. private void ensureCapacityInternal(int minCapacity) {
         //这里elementData==EMPTY_ELEMENTDATA 也就是上面无参构造方法里的的赋值, 所以这里的判断可以理解为是否是第一次添加元素时调用此方法
  21. if (elementData == EMPTY_ELEMENTDATA) {
  22. //如果是第一次添加元素 minCapacity应该为0+1 所以这里把DEFAULT_CAPACITY也就是10赋值给minCapacity
  23. minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
  24. }
  25.  
  26. ensureExplicitCapacity(minCapacity);
  27. }
  28.  
  29. private void ensureExplicitCapacity(int minCapacity) {
  30. modCount++;
  31.  
  32. // overflow-conscious code
  33. //这里判断新添加一个元素以后 长度是否大于当前数组 如果大于则给数组扩容
         //如果是第一次添加元素 肯定是true 然后把10传到grow方法中去
  34. if (minCapacity - elementData.length > 0)
  35. grow(minCapacity);
  36. }
  37.  
  38. /**
  39. * Increases the capacity to ensure that it can hold at least the
  40. * number of elements specified by the minimum capacity argument.
  41. *
  42. * @param minCapacity the desired minimum capacity
  43. */
  44. private void grow(int minCapacity) {
  45. // overflow-conscious code
  46. int oldCapacity = elementData.length;
  47. //这里是给扩容后的数组定义的长度
  48. int newCapacity = oldCapacity + (oldCapacity >> 1);
         //如果是第一次添加元素 new肯定是小于min的 所以把10赋给newCapacity 用来创建长度为10的新数组
  49. if (newCapacity - minCapacity < 0)
  50. newCapacity = minCapacity;
  51. if (newCapacity - MAX_ARRAY_SIZE > 0)
  52. newCapacity = hugeCapacity(minCapacity);
  53. // minCapacity is usually close to size, so this is a win:
  54. //把原来的数组copy到新数组中 如果是第一次add 则创建了一个长度为10的数组
  55. elementData = Arrays.copyOf(elementData, newCapacity);
  56. }
  57.  
  58. private static int hugeCapacity(int minCapacity) {
  59. if (minCapacity < 0) // overflow
  60. throw new OutOfMemoryError();
  61. return (minCapacity > MAX_ARRAY_SIZE) ?
  62. Integer.MAX_VALUE :
  63. MAX_ARRAY_SIZE;
  64. }

通过上面的代码 我们可以发现:

在第一次给集合添加元素的时候 的确会通过add方法及方法内调用的其他方法 创建一个长度为10的数组

并且以后每次add的时候 都会先判断一下 size+1是否超过了数组的长度 如果超过了长度就重新定义一个长度  int newCapacity = oldCapacity + (oldCapacity >> 1);的数组 然后把旧数组复制到新创建的数组中返回

解释一下 int newCapacity = oldCapacity + (oldCapacity >> 1);    (oldCapacity >> 1)的意思是oldCapacity转换成2进制然后右移一位 也就是oldCapacity /2

综上所述 第一次给集合添加元素的时候 集合中数组的长度会被设置成10   每次数组元素满了以后 重新给数组设置的长度为  原数组长度+(原数组长度/2) (这里跟C#不同,C#中是初始长度为4 新数组长度=原数组长度*2)

java基础之集合长度可变的实现原理的更多相关文章

  1. Java基础之 集合体系结构(Collection、List、ArrayList、LinkedList、Vector)

    Java基础之 集合体系结构详细笔记(Collection.List.ArrayList.LinkedList.Vector) 集合是JavaSE的重要组成部分,其与数据结构的知识密切相联,集合体系就 ...

  2. java基础-Map集合

    java基础-Map集合 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Map集合概述 我们通过查看Map接口描述,发现Map接口下的集合与Collection接口下的集合,它 ...

  3. 第6节:Java基础 - 三大集合(上)

    第6节:Java基础 - 三大集合(上) 本小节是Java基础篇章的第四小节,主要介绍Java中的常用集合知识点,涉及到的内容包括Java中的三大集合的引出,以及HashMap,Hashtable和C ...

  4. 备战金三银四!一线互联网公司java岗面试题整理:Java基础+多线程+集合+JVM合集!

    前言 回首来看2020年,真的是印象中过的最快的一年了,真的是时间过的飞快,还没反应过来年就夸完了,相信大家也已经开始上班了!俗话说新年新气象,马上就要到了一年之中最重要的金三银四,之前一直有粉丝要求 ...

  5. java基础技术集合面试【笔记】

    java基础技术集合面试[笔记] Hashmap: 基于哈希表的 Map 接口的实现,此实现提供所有可选的映射操作,并允许使用 null 值和 null 键(除了不同步和允许使用 null 之外,Ha ...

  6. Java基础知识--集合

    集合类 数组和集合的比较:数组可以存储对象,也可以存储基本数据类型,但是缺点就是长度固定,不能改变:集合长度是可变的,但是集合只能存储对象,集合可以存储不同类型的对象. Java容器类库一共有两种主要 ...

  7. 《回炉重造 Java 基础》——集合(容器)

    整体框架 绿色代表接口/抽象类:蓝色代表类. 主要由两大接口组成,一个是「Collection」接口,另一个是「Map」接口. 前言 以前刚开始学习「集合」的时候,由于没有好好预习,也没有学好基础知识 ...

  8. 黑马程序员——【Java基础】——集合框架

    ---------- android培训.java培训.期待与您交流! ---------- 一.集合框架概述 (一)集合框架中集合类关系简化图 (二)为什么出现集合类? 面向对象语言对事物的体现都是 ...

  9. Java基础--说集合框架

    版权所有,转载注明出处. 1,Java中,集合是什么?为什么会出现? 根据数学的定义,集合是一个元素或多个元素的构成,即集合一个装有元素的容器. Java中已经有数组这一装有元素的容器,为什么还要新建 ...

随机推荐

  1. C 时间函数总结

    头文件 time.h 处理器时间函数 clock_t clock(void) 处理器的处理时间,如可以在 main开始的地方 使用这个函数,然后再 完毕后 调用这个函数 并 减去 之前的返回值,为了 ...

  2. 解决 Laravel/Lumen 出现 "Please provide a valid cache path" 问题

    解决 Laravel/Lumen 出现 "Please provide a valid cache path" 问题 解决 Laravel/Lumen 出现 "Pleas ...

  3. HTML服务器控件与Web服务器控件

    asp.net之所以现在开发方便和快捷,关键是它有一组强大的控件库,包括web服务器控件,web用户控件,web自定义控件,html服务器控件和html控件等.这里主要整理一下html控件.html服 ...

  4. matlab中hdl coder 的使用

    今天摸索了一下hdl coder的使用方法,各个步骤主要是照猫画虎,有些地方还是不理解,先总结一下: 1.要想调用quartus或者Xilinx综合布局布线需要先设置,设置的方法有两种,命令窗口输入 ...

  5. Hadoop体系结构之 HDFS

    HDFS采用主从(Master/Slave)结构模型,一个HDFS集群是由一个NameNode和若干个DataNode组成的(在最新的Hadoop2.2版本已经实现多个NameNode的配置-这也是一 ...

  6. UCloud 云服务器硬盘扩容后 如何挂载到本机

    UCloud 云服务器硬盘扩容后如何挂载到本机 UCloud 提供的云服务器会根据不同的系统初始化不同空间大小的硬盘资源,此资源默认为 系统盘. 针对 Linux 系统默认初始化 20G 的空间,一般 ...

  7. laravel 二维码生成器包 QrCode 的使用

    在laravel中使用 QrCode 生成二维码 https://laravelacademy.org/post/2605.html 我在本机的windows下composer require 没有成 ...

  8. (转)oracle - type

    本文转载自:http://www.cnblogs.com/o-andy-o/archive/2012/05/25/2517741.html type定义: oracle中自定义数据类型oracle中有 ...

  9. Java-Runoob-高级教程:Java MySQL 连接

    ylbtech-Java-Runoob-高级教程:Java MySQL 连接 1.返回顶部 1. Java MySQL 连接 本章节我们为大家介绍 Java 如何使用 使用 JDBC 连接 MySQL ...

  10. win7 网站发布备注

    1.更改 .NET Framework 版本(改原设置v2.0 为v4.0) 2.程序池设置 3.基本设置 4.Web.config (debug="false") <sys ...