范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

ArrayList全面详解(看这篇就够了)

  ArrayList属于Java集合框架最常用的集合,本篇会详解ArrayList的使用与源码 @mikechenArrayList的定义
  ArrayList 是 java 集合框架中比较常用的数据结构了,实现了 List 接口。
  ArrayList相当于动态数组,与Java中的数组相比,它的容量能动态增长。ArrayList的特点允许插入重复的元素插入的元素是有序的动态扩容非线程安全基于动态数组的数据结构擅长随机访问(get set)ArrayList的成员变量public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, Serializable {   // 实际元素个数 private int size;    // 存放的元素集合 transient Object[] elementData;    // 默认初始大小10 private  static  final  int DEFAULT_CAPACITY = 10;    //记录对List操作的次数,主要使用在Iterator中,防止迭代过程中集合被修改 protected  transient  int modCount = 0;      // 下面两个变量用在构造函数中,判断第一次添加元素时知道从空的构造函数还是有参构造函数被初始化的 private static final Object[] EMPTY_ELEMENTDATA = {}; private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};       // ... }ArrayList的构造函数
  1. 无参数构造//无参数的构造方法     public ArrayList() {         //此时 elementData为{}         this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;     }
  构造一个初始容量为10的空的list集合,但构造函数只是给elementData赋值了一个空的数组,其实是在第一次添加元素时扩大至10。2.有参构造函数/** * Constructs an empty list with the specified initial capacity. * * @param  initialCapacity  the initial capacity of the list * @throws IllegalArgumentException if the specified initial capacity *         is negative */ 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);     } }
  只要保证传递参数值 不 < o,即可,小于 0,会抛异常。3.集合参数构造函数 public ArrayList(Collection<? extends E> c) {         elementData = c.toArray(); //转为数组         if ((size = elementData.length) != 0) { //集合大小不等于0             // c.toArray might (incorrectly) not return Object[] (see 6260652)             if (elementData.getClass() != Object[].class)//集合类型不是Object类型                 elementData = Arrays.copyOf(elementData, size, Object[].class);//复制         } else {//集合大小为0,指定一个空数组             // replace with empty array.             this.elementData = EMPTY_ELEMENTDATA;         }     }ArrayList的API// Collection中定义的API boolean             add(E object) boolean             addAll(Collection<? extends E> collection) void                clear() boolean             contains(Object object) boolean             containsAll(Collection<?> collection) boolean             equals(Object object) int                 hashCode() boolean             isEmpty() Iterator         iterator() boolean             remove(Object object) boolean             removeAll(Collection<?> collection) boolean             retainAll(Collection<?> collection) int                 size()  T[]             toArray(T[] array) Object[]            toArray() // AbstractCollection中定义的API void                add(int location, E object) boolean             addAll(int location, Collection<? extends E> collection) E                   get(int location) int                 indexOf(Object object) int                 lastIndexOf(Object object) ListIterator     listIterator(int location) ListIterator     listIterator() E                   remove(int location) E                   set(int location, E object) List             subList(int start, int end) // ArrayList新增的API Object               clone() void                 ensureCapacity(int minimumCapacity) void                 trimToSize() void                 removeRange(int fromIndex, int toIndex)ArrayList主要方法解析
  1.add增加 public boolean add(E e) {//添加一个元素         ensureCapacityInternal(size + 1);  // Increments modCount!!         elementData[size++] = e; //长度+1         return true; //返回boolean 类型     }          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++;//长度+1     }         private void ensureCapacityInternal(int minCapacity) {         ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));//默认长度10     }        private void ensureExplicitCapacity(int minCapacity) {         modCount++;//记录修改次数              //         if (minCapacity - elementData.length > 0)//传入长度大于当前长度,扩容             grow(minCapacity);     }     private void grow(int minCapacity) {         // overflow-conscious code         int oldCapacity = elementData.length;//老容量         int newCapacity = oldCapacity + (oldCapacity >> 1);//老容量+ 老容量/2         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);//扩容拷贝     }        private static int hugeCapacity(int minCapacity) {         if (minCapacity < 0) // overflow 传入容量 < 0 抛异常             throw new OutOfMemoryError();         return (minCapacity > MAX_ARRAY_SIZE) ?             Integer.MAX_VALUE :             MAX_ARRAY_SIZE;     }
  添加元素时,会指定默认为10的容量,当添加元素导致集合容量大于10,触发扩容机制,扩容为原来的1.5倍。2.remove移除   public E remove(int index) {         //校验删除位置是否合理         rangeCheck(index);       // 同add理由一样         modCount++;        // 保存待删除元素         E oldValue = elementData(index);         // 判断删除位置:如果>0不在尾部需要调用System.arraycopy,否则在尾部直接删除         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;     }
  当我们调用 remove(int index) 时,首先会检查 index 是否合法,然后再判断要删除的元素是否位于数组的最后一个位置。
  如果 index 不是最后一个,就再次调用 System.arraycopy() 方法拷贝数组。
  如果 index 是最后一个元素那么就直接将数组的最后一个位置空,size - 1即可。3.get获取    public E get(int index) { //获取指定索引的值         rangeCheck(index);//是否越界          return elementData(index);//返回指定下标的值     }     private void rangeCheck(int index) {         if (index >= size) //索引大于 集合长度,抛异常             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));     }
  由于ArrayList底层是基于数组实现的,所以获取元素就相当简单了,直接调用数组随机访问即可。4.set修改public class ArrayList extends AbstractList         implements List, RandomAccess, Cloneable, java.io.Serializable{     public E set(int index, E element) {         rangeCheck(index);          E oldValue = elementData(index);         elementData[index] = element;         return oldValue;     }}
  修改指定位置的元素为新元素,首先需要校验给定index的值,index必须大于等于0,小于size,然后将新元素保存到index位置,并将旧元素返回。5.扩容操作public void ensureCapacity(int minCapacity) {         //修改计时器         modCount++;         //ArrayList容量大小         int oldCapacity = elementData.length;         /*          * 若当前需要的长度大于当前数组的长度时,进行扩容操作          */         if (minCapacity > oldCapacity) {             Object oldData[] = elementData;             //计算新的容量大小,为当前容量的1.5倍             int newCapacity = (oldCapacity * 3) / 2 + 1;             if (newCapacity < minCapacity)                 newCapacity = minCapacity;             //数组拷贝,生成新的数组             elementData = Arrays.copyOf(elementData, newCapacity);         }     }
  ensureCapacityInternal方法的目的是确保给定的参数指定的容量值。
  真正的扩容逻辑位于grow方法中:public class ArrayList extends AbstractList         implements List, RandomAccess, Cloneable, java.io.Serializable{     private void grow(int minCapacity) {         // overflow-conscious code         int oldCapacity = elementData.length;         int newCapacity = oldCapacity + (oldCapacity >> 1);// 扩容为原容量的1.5倍         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);     }     // 处理超限问题     // 如果给定的minCapacity为负数(首位为1)则抛出异常错误OutOfMemoryError     // 如果给定容量大于数组最大容量,则取整数的最大值为容量,否则使用数组的最大容量作为扩容容量     private static int hugeCapacity(int minCapacity) {         if (minCapacity < 0) // overflow             throw new OutOfMemoryError();         return (minCapacity > MAX_ARRAY_SIZE) ?             Integer.MAX_VALUE :             MAX_ARRAY_SIZE;     }}
  ensureCapacity(),该方法就是ArrayList的扩容方法,每次扩容处理会是1.5倍。
  1.5倍的扩容是最好的倍数,因为一次性扩容太大(例如2.5倍)可能会浪费更多的内存(1.5倍最多浪费33%,而2.5被最多会浪费60%,3.5倍则会浪费71%……)。
  但是一次性扩容太小,需要多次对数组重新分配内存,对性能消耗比较严重。
  所以1.5倍刚刚好,既能满足性能需求,也不会造成很大的内存消耗。Fail-Fast机制
  在我们每次操作集合的时候,都会记录一个修改次数。
  modCount++ 其实他就是fail-fast机制,它是Java集合的一种错误检测机制。
  当多个线程对集合进行结构上的改变的操作时,有可能会产生fail-fast机制。记住是有可能,而不是一定。例如:假设存在两个线程(线程1、线程2),线程1通过Iterator在遍历集合A中的元素,在某个时候线程2修改了集合A的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出 ConcurrentModificationException 异常,从而产生fail-fast机制。ArrayList总结
  最后做一下总结,知识点归纳:ArrayList底层采用数组实现,拥有快速随机访问能力,但是非线程安全的集合。ArrayList默认容量为10,扩容规则为当要保存的新元素所需的容量不足时触发。扩容机制为首先扩容为原始容量的 1.5 倍。扩容之后是通过数组的拷贝来确保元素的准确性的,所以尽可能减少扩容操作。如果在遍历的时候发生结构性变化,会触发ConcurrentModificationException异常。结构性变化包括:添加新元素,删除元素。
  更多架构技术干货,私信【架构】即可查看我原创的300期+BAT架构技术系列文章与1000+大厂面试题答案合集。

理想汽车发布财报首次实现盈利,四季度营收增长65中国造车新势力之一理想汽车报告2020年第四季度净利润1。075亿人民币,其在中国市场的营收增长抵消了高昂的生产成本。理想汽车是三大造车新势力中第一个发布财报的公司,蔚来汽车和小鹏91十条新能源汽车行业的每日必读简报(210301)中国消费者协会公布2020年全国消协组织受理投诉情况分析,汽车及零部件在2020年以全年34897的投诉量排第二位,仅次于食品行业。2。特斯拉(上海)有限公司经营范围新增新能源汽车91十条新能源汽车行业的每日必读简报(210302)1戴姆勒卡车和沃尔沃集团宣布组建的合资公司正式组建完成,原本公司名为DaimlerTruckFuelCellGmbHCo。KG,现双方同意更改为cellcentricGmbHCo。全球最快的磁吸无线充电出自真我,这次realme走在所有大厂的前面对于realme这个品牌,给大家的印象一向都是不断推出一些性比价的手机,说白了就是跟小米一样,都是以性价比的产品而为人熟知。但realme只会做性比价吗?显然不是,不久前realmJ。D。POWER最佳认证的车企翻车,起亚召回38万辆汽车韩系车在国内越来越没有存在感。不过不得不承认,韩系车在全球的表现仍然可圈可点,尤其是在质量稳定性方面,一直受到业界与消费者认可。根据J。D。POWER发布的2019年美国新车质量研91十条新能源汽车行业简报大众纯电汽车明年销量或超特斯拉1美系车电动化动作加快,福特推出了纯电动版MustangMachE车型,GT版本最大功率为342kW,峰值扭矩830Nm,百公里加速仅为3。5秒。2芜湖奇瑞信息技术有限公司宣布,奇大众汽车全面停止燃油车研发,2025年称霸全球电动车市场作为电动汽车时代的开启者,特斯拉在全球拥有品牌和市场先发优势,这一点已经充分体现在了销量上。与此同时,作为燃油车时代的霸主,大众汽车在电动汽车时代动作迟缓。如今,大众汽车也已经开始关于2020年注册亚马逊全球开店的非官方消息据亚马逊非官方的消息,亚马逊已经暂停贸易商下发注册链接,也就是说,现在想拿到注册链接,必须至少有商标注册。不过,注册链接也会越来越少,门槛越来越高,已经8月31号了哦,哥哥9月份想91十条新能源汽车行业的每日必读简报(210311)1五菱汽车官方宣布,演员任敏马伯骞将出任宏光MINIEV代言人,新车官图也一同公布。2大众集团首席战略官MichaelJost将离职,他给出的理由是现在智能化变革已经轮到轮船领域,91十条中国出口澳大利亚汽车暴涨,创维表示将再投入300亿造车1长安汽车计划加大新能源领域的布局,未来将有26款纯电动车型陆续推出,其中内部代号分别为E11和C385的两款主打智能化的车型有望在年内亮相。这26款新车包括长安品牌8款插电混动车91十条高通汽车订单超80亿美元,博世在华年收入达888亿元1高通表示,目前全球有超过1。5亿辆汽车采用高通汽车解决方案,25家顶级车企有20家用了高通骁龙数字座舱平台。高通汽车解决方案订单总估值超80亿美元,包括车载网联信息娱乐和车内连接
苹果日历怎么添加日程添加日程用这款日历便签苹果手机上的日历app是很多人平时都会接触到的一款软件,在使用日历app的时候,不但可以方便的查看日期,还可以在日历中添加日程方便自己记录和查看。苹果日历怎么添加日程呢?添加日程用ios纪念日app哪款值得推荐?快收下这款便签人们的一生当中会有很多个精彩难忘的时刻,为了把这些日子记的更牢,不少人会给一些事情设定纪念日,比如结婚纪念日等等。在使用ios系统手机的时候,可以通过各种app来辅助自己,ios纪外贸大佬的看家工具有哪些01hrIP地址自检DNSBL若你发出的邮件老是被退回,社交账号也无缘无故被封,那么你应该检查下你的IP地址了,看是否被收录进了黑名单。若被拉进了黑名单申诉及后期真的超麻烦。为了方精益求精的懒癌患者,家里怎么少得了一款智能扫地机器人精益求精的长期懒癌患者,对于家务活这种事情当然是能偷懒就偷懒的,那么家务活谁来干呢?所以拥有一台属于自己的智能扫地机器人就很重要了。我们可以让它协助我们清洁地面,这样会大大节省我们北京香山公园,初秋的周末赏红叶北京现在已是初秋时节,天气逐渐变凉,已经过了霜降节气,一早一晚也有了寒意。此时街道两旁的树叶已经开始变黄,每天早晨都会有一部分率先落于树下,被环卫工人清扫后堆积在路边。街道上的落叶这家欧洲小厂造的跑车时速可达400公里上海到北京3小时到达借助电动化趋势造车的企业不止有中国的蔚来和小鹏,来自瑞士的MorandCars新能源车企近日发布消息称,要在2023年推出一款最高时速突破400kmh的超级跑车。同时官方表示,新车Spacex星舰最快11月开始首次轨道飞行,一小时内两次完成静态点火振奋人心,Spacex星舰二级SN20一小时内完成两次静态点火,现场效果看挺好,持续时间也有2秒以上,就是掉了几片隔热瓦。星舰静态点火自从SN15原型机成功实现10公里飞行以后,s扫地机器人真的好用吗?扫地机器人怎么选?过来人告诉你为了解决自己动手扫地拖地的苦恼,越来越多的人群开始使用扫地机器人。智能扫地机器人的出现,在日常的家居生活中为我们减少很多的劳务负担。但是有人就会问了扫地机器人真的好用吗?扫地机器人小洁扫地机器人体验这玩意儿简直就是懒人最爱作为一个资深的懒癌患者,最头疼的莫过于每天在家扫地了。拥有扫地机器人之后,似乎也没轻松多少虽然不需要我动手了,但原来的扫地机器人没法准确寻路。每次扫之前,都得大费周章地把椅子凳子搬一场属于扫地机器人的革命评测SEGOO小洁扫地机好用吗辛辛苦苦上了一天班还在因为下班后没精力打扫卫生而感到无力吗?总想抽出时间打扫卫生,但却总因为各种理由迟迟没有打扫吗?还在犹豫要不要买一台扫地机器人吗?不妨试试SEGOO小洁扫地机器扫地机器人该怎么选?最强选购攻略每个人都希望自己家里是明媚干净一尘不染的。家居环境直接影响一个人的心情,如果家里乱糟糟的或者地面满是灰尘,我们看到心情也不会好的,舒适干净的家居生活能提高我们生活的幸福感。所以现在