ArrayList简介 ArrayList 是一个数组队列,相当于 动态数组。与Java中的数组相比,它的容量能动态增长。它继承于AbstractList,实现了List, RandomAccess, Cloneable, java.io.Serializable这些接口。 ArrayList 继承了AbstractList,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。ArrayList 实现了RandmoAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在ArrayList中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问。稍后,我们会比较List的“快速随机访问”和“通过Iterator迭代器访问”的效率。 ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。 ArrayList 实现java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输。 和Vector不同,ArrayList中的操作不是线程安全的!所以,建议在单线程中才使用ArrayList,而在多线程中可以选择Vector或者CopyOnWriteArrayList。 ArrayList 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用ensureCapacity操作来增加 ArrayList 实例的容量。这可以减少递增式再分配的数量。 它继承于 AbstractList,实现了 List, RandomAccess, Cloneable, java.io.Serializable 这些接口。 在我们学数据结构的时候就知道了线性表的顺序存储,插入删除元素的时间复杂度为O(n),求表长以及增加元素,取第 i 元素的时间复杂度为O(1) 底层使用数组保存所有元素,默认情况下初始化空数组(长度为0的数组),通过指定数组来初始容量: 1. 当指定的初始容量大于0,初始化指定大小的数组 2. 当指定的初始容量等于0,初始化空数组 3. 当指定的初始容量小于0,抛出IllegalArgumentException异常 长度超过10以后,进行扩容,扩容是原来长度的1.5倍.通过调用add()或者addAll()方法触发 ArrayList智能存储对象,不能存储基本数据类型,所以泛型不能写基础数据类型 ArrayList 继承了AbstractList,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。 ArrayList 实现了RandomAccess 接口, RandomAccess 是一个标志接口,表明实现这个这个接口的 List 集合是支持快速随机访问的。在 ArrayList 中,我们即可以通过元素的序号快速获取元素对象,这就是快速随机访问。 ArrayList 实现了Cloneable 接口,即覆盖了函数 clone(),能被克隆。 ArrayList 实现java.io.Serializable 接口,这意味着ArrayList支持序列化,能通过序列化去传输。 和 Vector 不同,ArrayList 中的操作不是线程安全的!所以,建议在单线程中才使用 ArrayList,而在多线程中可以选择 Vector 或者 CopyOnWriteArrayList。
1.API ,核心源码,遍历方式,toArray异常 参考: https://www.yuque.com/docs/share/522a0586-2a58-4649-8ae0-47468bba7e3a?#
2.System.arraycopy()和Arrays.copyOf()方法区别 Arrays.copyOf()会返回一个新数组。该新数组在方法内部被创建 System.arraycopy()需要预先创建好一个目标数组,且不会返回任何值(将原数组拷贝到你自己定义的数组里面,而且可以选择拷贝的起点和长度以及放入新数组中的位置)。比如当希望数据的操作在原数组中进行时,只需将原数组作为目标数组即可。 Arrays.copyOf()实际上是调用了System.arraycopy() System.arraycopy() 在拷贝数组的时候,采用的使用浅复制,复制结果是一维的引用变量传递给副本的一维数组,修改副本时,会影响原来的数组,System.arraycopy()也是线程不安全的. 关于性能问题,当测试数组的范围比较小的时候,两者相差的时间无几,当测试数组的长度达到百万级别,System.arraycopy的速度优势就开始体现了,根据对底层的理解,System.arraycopy是对内存直接进行复制,减少了for循环过程中的寻址时间,从而提高了效能。 在看ArrayList源码时看见,当扩容时采取的是Arrays.copyOf(),插入或删除时使用的是System.arrayCopy()方法. add(int index, E element)方法就很巧妙的用到了arraycopy()方法让数组自己复制自己实现让index开始之后的所有成员后移一个位置 详细: https://www.yuque.com/docs/share/9daeba8c-c851-48a3-bf8d-7755aa2b578d?#
3.jdk8扩容技术 当ArrayList不为空时,并且它的大小不超过10时,它的容量都是10.但当大小从10增加到11时,容量变成了15,扩大了1.5倍. 也有人说jdk1.6版本以后,ArrayList扩容后的容量为1.5倍加1. 扩容原理参考下面的:https://www.yuque.com/docs/share/6a9f492e-e587-4c0f-a1e9-95db6d2be359
4.内部类(1)private class Itr implements Iterator (2)private class ListItr extends Itr implements ListIterator (3)private class SubList extends AbstractList implements RandomAccess (4)static final class ArrayListSpliterator implements Spliterator ArrayList有四个内部类,其中的Itr是实现了Iterator接口,同时重写了里面的hasNext(),next(),remove()等方法;其中的ListItr继承Itr,实现了ListIterator接口,同时重写了hasPrevious(),nextIndex(),previousIndex(),previous(),set(E e),add(E e)等方法,所以这也可以看出了 Iterator和ListIterator的区别:ListIterator在Iterator的基础上增加了添加对象,修改对象,逆向遍历等方法,这些是Iterator不能实现的。
5.循环遍历添加值都是最后一次的值从网上找个答案,结果是当添加值的时候并不是添加实体类,而是实体类的引用,相当于指针,存储的也是存储的指针,所以我添加的都是最后一次的引用,这个引用没有变化,所以最后arraylist中的数据指向都是最后一次封装的值,所以当往ArrayList循环添加数据的时候需要重新new对象.
ArrayList resultList = new ArrayList<>();for (int i = 0; i < yearList.size(); i++) { HashMap DateMap = new HashMap<>();//每次循环的时候都需要new对象 String creationTimeYear = (String) yearList.get(i).get(“creationTimeYear” );//每次循环的日期中的年 DateMap.put(“year” , creationTimeYear);//组装年数据 map.put(“year” , creationTimeYear); //通过起始地址和结束地址和年查询月份集合 String[] monthArray = this .appUserOrderDao .selectMonthDataByStartAddressAndEndAddress(map); DateMap.put(“month” , monthArray); map.put(“year” , creationTimeYear);//每次循环的日期中的年 resultList.add(DateMap); }
6.利用set集合去根据map的指定key去重复 /cityList的数据: {“status”:1,”message”:”请求成功”, “data”:[ {“city1”:”台北市”,”longitude1”:121.520076,”latitude1”:25.030724}, {“city1”:”金门县”,”longitude1”:118.32277,”latitude1”:24.42931}, {“city1”:”台北市”,”longitude1”:121.541766,”latitude1”:25.074708}, {“city1”:”金门县”,”longitude1”:118.326118,”latitude1”:24.430389} ]} / List> cityList = this .appUserOrderDao .selectCity(map); //对结果去重复 HashSet citySet = new HashSet<>(); List> resultMapList = new ArrayList<>();for (Map cityMap : cityList) { if (citySet.add(cityMap.get(“city1” ))) { //如果重复了就添加失败就返回了false,否则就返回了true resultMapList.add(cityMap); } }
return JsonUtils.objectToJson (new JsonResult(resultMapList)); 结果: { “status”: 1, “message”: “请求成功”, “data”: [ { “city1”: “台北市”, “longitude1”: 121.520076, “latitude1”: 25.030724 }, { “city1”: “金门县”, “longitude1”: 118.32277, “latitude1”: 24.42931 } ] }
7.根据集合里面对象的某一个成员属性去重复 比如根据集合里面的对象的id进行去重复, waterMenus 是一个List集合,泛型是 waterMenu List waterMenuList = waterMenus.stream().collect( Collectors.collectingAndThen (Collectors.toCollection ( () -> new TreeSet<>(Comparator.comparing (o -> o.getId()))), ArrayList::new ));
8.list集合去重复list集合去重复 List yearList = this .appUserOrderDao .selectTimeListYear(map); //list集合去重复 yearList = (List) yearList.stream().distinct().collect(Collectors.toList ());
(二)解决方案
1.集合判空 import org.springframework.util.CollectionUtils ArrayList objects = new ArrayList<>(); System.out .println(CollectionUtils.isEmpty (objects)); org.springframework.util.ObjectUtils ArrayList arrayList = new ArrayList() ;boolean empty = ObjectUtils.isEmpty (arrayList);
2.合并数组到指定的集合里面import org.springframework.util.CollectionUtils String[] a = new String[]{“a” , “b” }; ArrayList strings = new ArrayList<>(); strings.add(“aa” ); strings.add(“bb” ); CollectionUtils.mergeArrayIntoCollection (a, strings);
3.查询这个集合里面的数据是否在别的集合里面存在import org.springframework.util.CollectionUtils List integers1 = Arrays.asList (1, 2, 3, 4, 5); ArrayList integers = new ArrayList<>(integers1); ArrayList a = new ArrayList<>(integers1);
ArrayList integers2 = new ArrayList<>(Arrays.asList (1, 25, 154, 112)); boolean b = CollectionUtils.containsAny (integers, a);//true boolean b1 = CollectionUtils.containsAny (integers1, integers2); //true
4.检查元素在指定的集合是否存在import org.springframework.util.CollectionUtils List integers1 = Arrays.asList (1, 2, 3, 4, 5); ArrayList integers = new ArrayList<>(integers1);boolean b = CollectionUtils.containsInstance (integers, 1);//trueboolean b1 = CollectionUtils.containsInstance (integers, 10);//false
5.在两个集合里面检索第一个重复的值 import org.springframework.util.CollectionUtils //两个集合第一个重复的值是55 ,所以就返回 55 ArrayList aa = new ArrayList<>(Arrays.asList (1, 55, 3, 4, 5)); ArrayList bb = new ArrayList<>(Arrays.asList (11, 55, 3, 66, 165));
Integer firstMatch = CollectionUtils.findFirstMatch (aa, bb); // 55 //两个集合第一个重复的值是1 , 所以就返回 1 Integer b = CollectionUtils.findFirstMatch (new ArrayList<>(Arrays.asList (1, 55, 3, 4, 5)), aa);//1
(三)Collections工具类 Collections工具类 该工具类提供了大量针对Collection/Map的操作,总体可分为四类,都为静态(staic)方法: 1、排序操作(主要针对List接口相关) reverse(List list):反转指定List集合中元素的顺序 shuffle(List list):对List中的元素进行随机排序(洗牌) sort(List list):对List里的元素根据自然升序排序 sort(List list,Comparator c):自定义比较器进行排序 swap(List list,int i,int j):将指定List集合中i 处元素和j 处元素进行交换 rotate(List list,int distance):将所有元素向右移位指定长度,如果distance等于size那么结果不变 2、查找和替换(主要针对Collection接口相关) binarySearch(List list,Object key):使用二分法查找,以获得指定对象在List中的索引,前提是集合已经排序 max(Collection coll):返回最大元素 max(Collection coll,Comparator comp):根据自定义比较器,返回最大元素 min(Collection] coll):返回最小元素 min(Collection coll,Comparator comp):根据自定义比较器,返回最小元素 fill(List list,Object obj):使用指定对象填充 frequency(Collection Object obj):返回指定集合中指定对象出现的次数 replaceAll(List list,Object old,Object new):替换 int frequency(Collection c, Object o)//统计元素出现次数 int indexOfSubList(List list, List target)//统计target在list中第一次出现的索引,找不到则返回-1,类比int lastIndexOfSubList(List source, list target). 3、同步控制(不要用,效率低,直接用juc包下的并发集合) 4、设置不可变得结合 Collections工具类有三种方法返回一个不可变集合 emptyXxx(): 返回一个空的不可变的集合对象 singletonXxx(): 返回一个只包含指定对象的,不可变的集合对象 unmodifiableXxx(): 返回指定集合对象的不可变视图 5、其它 disjoint(Collections<?>c1,Collections<?>c2) 如果两个指定collection中没有相同的元素,则返回true addAll(Collection<?super T>c,T…a) 一种方便的方式,将所有指定元素添加到指定collection中 ComparatorreverseOrder(Comparatorcmp)返回一个比较器,它强行反转指定比较器的顺序。如果指定比较器为null,则 此方法等同于reverseOrder(){返回一个比较器,它对实现 Comparable接口的对象集合施加了 自然排序的相反} 参考:https://www.yuque.com/docs/share/2a13c89a-1028-408f-bea7-8e19dcf2d82d?#
(四)Arrays工具类 1. 排序 : sort() 2. 查找 : binarySearch() 3. 比较: equals() 4. 填充 : fill() 5. 转列表: asList() 6. 转字符串 : toString() 7. 复制: copyOf() 具体代码看这里: