Java语言集合框架:ArrayList
龚超 2018-05-25 来源 : 阅读 796 评论 0

摘要:本文主要向大家介绍了Java语言集合框架ArrayList,通过定义概述举例,让大家能够了解ArrayList,希望对大家学习Java语言有所帮助。

本文主要向大家介绍了Java语言集合框架ArrayList,通过定义概述举例,让大家能够了解ArrayList,希望对大家学习Java语言有所帮助。

ArrayList定义

   

package java.util;
public class ArrayListextends AbstractList
        implements List, RandomAccess, Cloneable, java.io.Serializable{
    private static final int DEFAULT_CAPACITY = 10;
    private static final Object[] EMPTY_ELEMENTDATA = {};
    private transient Object[] elementData;
    private int size;
//其余省略
}

   


 

ArrayList概述

ArrayList以数组实现,允许重复。超出限制时会增加50%的容量(grow()方法中实现,如下所示),每次扩容都底层采用System.arrayCopy()复制到新的数组,因此最好能给出数组大小的预估值。默认第一次插入元素时创建数组的大小为10.



private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        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);
    }

   


按数组下标访问元素—get(i)/set(i,e) 的性能很高,这是数组的基本优势。



public E get(int index) {
        rangeCheck(index);
 
        return elementData(index);
    }
    public E set(int index, E element) {
        rangeCheck(index);
 
        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

   


直接在数组末尾加入元素—add(e)的性能也高,但如果按下标插入、删除元素—add(i,e), remove(i), remove(e),则要用System.arraycopy()来移动部分受影响的元素,性能就变差了,这是基本劣势。

   

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    public void add(int index, E element) {
        rangeCheckForAdd(index);
 
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }
    public E remove(int index) {
        rangeCheck(index);
 
        modCount++;
        E oldValue = elementData(index);
 
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
 
        return oldValue;
    }
    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

   


ArrayList中有一个方法trimToSize()用来缩小elementData数组的大小,这样可以节约内存:



public void trimToSize() {
       modCount++;
       if (size < elementData.length) {
           elementData = Arrays.copyOf(elementData, size);
       }
   }

   


考虑这样一种情形,当某个应用需要,一个ArrayList扩容到比如size=10000,之后经过一系列remove操作size=15,在后面的很长一段时间内这个ArrayList的size一直保持在<100以内,那么就造成了很大的空间浪费,这时候建议显式调用一下trimToSize()这个方法,以优化一下内存空间。
或者在一个ArrayList中的容量已经固定,但是由于之前每次扩容都扩充50%,所以有一定的空间浪费,可以调用trimToSize()消除这些空间上的浪费。
非线程安全,可以调用Collections.synchronizedList(new ArrayList<>());实现。

 

ArrayList的使用

举个简单一点的例子:



Listlist = new ArrayList<>();
      list.add(4);
      list.add(2);
      list.add(3);
      list.add(5);
      for(int i:list)
      {
          System.out.println(i);
      }
      System.out.println(list);

   


运行结果:



[4, 2, 3, 5]

   


可以发现ArrayList是按插入顺序存储的,这也不奇怪,每次插入是在elementData[size++]处插入。

 

subList的使用



Listlist = new ArrayList<>();
      list.add(4);
      list.add(2);
      list.add(3);
      list.add(5);
      list.add(7);
      list.add(5);
      list.add(11);
      list.add(14);
      list.add(10);
      list.add(9);
      System.out.println(list);
      Listlist2 = list.subList(3, 6);
      System.out.println(list2);
      list2.set(2, 50);
 
      System.out.println("============");
      System.out.println(list);
      System.out.println(list2);

   


运行结果:



[4, 2, 3, 5, 7, 5, 11, 14, 10, 9]

[5, 7, 5]

============

[4, 2, 3, 5, 7, 50, 11, 14, 10, 9]

[5, 7, 50]

   


调用ArrayList中的subList方法生成的新的list,内部引用的还是原来的数组elementData,如果改变subList中的值,主list中的值也会跟着改变。

 

RandomAccess?!

但是,上面的程序有不合理之处!你们可能感到费解,请听我一一道来。
上面一段程序可以通过反编译看到oreach语法糖经过编译器处理成了Iterator的遍历,有关foreach语法糖的细节可以参考《Java语法糖之foreach》。由于上面程序反编译出来有100+行,太多了就不罗列了。只要知道一个事实就可以:foreach对于集合框架,编译解析成的是Iterator的遍历。
那么这又有什么不妥?集合框架印象中不就是用迭代器遍历的嚒?
注意ArrayList的特殊之处在于它implements了RandomAccess这个接口,在JDK中RandomAccess明确说明:



  It is recognized that the distinction between random and sequential access is often fuzzy. For example, some List implementations provide asymptotically linear access times if they get huge, but constant access times in practice. Such a List implementation should generally implement this interface. As a rule of thumb, a List implementation should implement this interface if, for typical instances of the class, this loop:

     for (int i=0, n=list.size(); i < n; i++)

         list.get(i);

 

runs faster than this loop:

     for (Iterator i=list.iterator(); i.hasNext(); )

         i.next();

   


这段英文主要说明的是实现了RandomAccess接口的集合框架,采用迭代器遍历比较慢,不推荐。
实现RandomAccess接口的集合有:ArrayList, AttributeList, CopyOnWriteArrayList, RoleList, RoleUnresolvedList, Stack, Vector等。
所以上面的例子中的遍历应该这么写:



int length = list.size();

      for(int i=0;i<length;i++)

      {

          System.out.println(list.get(i));

      }

   


其实也可以加个判断,让程序通用起来:




if (list instanceof RandomAccess)
       {
           for (int i = 0; i < list.size(); i++)
           {
           }
       }
       else
       {
           Iterator iterator = list.iterator();
           while (iterator.hasNext())
           {
               iterator.next();
           }
       }

   


因此,博主个人觉得JDK(jdk7)中有这么一段不妥之处(希望大神不要喷我):ArrayList的toString()方法是在AbstractCollection中实现的:



public String toString() {
      Iteratorit = iterator();
      if (! it.hasNext())
          return "[]";
 
      StringBuilder sb = new StringBuilder();
      sb.append('[');
      for (;;) {
          E e = it.next();
          sb.append(e == this ? "(this Collection)" : e);
          if (! it.hasNext())
              return sb.append(']').toString();
          sb.append(',').append(' ');
      }
  }

   


这里没有判断RandomAccess,直接采用的是迭代器的遍历,影响了一些性能。

 

ArrayList和LinkedList的区别

1. ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。

2. 对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。

3. 对于新增和删除操作add和remove,LinkedList比较占优势,因为ArrayList要移动数据。

 

ArrayList和Vector的区别

1. Vector和ArrayList几乎是完全相同的,唯一的区别在于Vector是同步类(synchronized),属于强同步类。因此开销就比ArrayList要大,访问要慢。正常情况下,大多数的Java程序员使用ArrayList而不是Vector,因为同步完全可以由程序员自己来控制。

2. Vector每次扩容请求其大小的2倍空间,而ArrayList是1.5倍。

3. Vector还有一个子类Stack.

如有问题请加微信号:Iotek666,本微信号会不定期推送技术相关优质文章、热点资讯、视频资源及生活趣事,也很乐意与您一起交流IT知识,让我们在闲暇之余巩固一下自己的知识体系 ,扩充一下自己的知识面。快利用琐碎时间给自己充电吧!

希望这篇文章可以帮助到你,总之同学们,it资讯尽在职坐标。


本文由 @职坐标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论
本文作者 联系TA

擅长针对企业软件开发的产品设计及开发的细节与流程设计课程内容。座右铭:大道至简!

  • 370
    文章
  • 23060
    人气
  • 87%
    受欢迎度

已有23人表明态度,87%喜欢该老师!

进入TA的空间
求职秘籍 直通车
  • 索取资料 索取资料 索取资料
  • 答疑解惑 答疑解惑 答疑解惑
  • 技术交流 技术交流 技术交流
  • 职业测评 职业测评 职业测评
  • 面试技巧 面试技巧 面试技巧
  • 高薪秘笈 高薪秘笈 高薪秘笈
TA的其他文章 更多>>
WEB前端必须会的基本知识题目
经验技巧 93% 的用户喜欢
Java语言中四种遍历List的方法总结(推荐)
经验技巧 91% 的用户喜欢
Java语言之SHA-256加密的两种实现方法详解
经验技巧 75% 的用户喜欢
java语言实现把两个有序数组合并到一个数组的实例
经验技巧 75% 的用户喜欢
通过Java语言代码来创建view的方法
经验技巧 80% 的用户喜欢
其他海同师资 更多>>
吕益平
吕益平 联系TA
熟悉企业软件开发的产品设计及开发
孔庆琦
孔庆琦 联系TA
对MVC模式和三层架构有深入的研究
周鸣君
周鸣君 联系TA
擅长Hadoop/Spark大数据技术
范佺菁
范佺菁 联系TA
擅长Java语言,只有合理的安排和管理时间你才能做得更多,行得更远!
金延鑫
金延鑫 联系TA
擅长与学生或家长及时有效沟通
经验技巧30天热搜词 更多>>

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程