一、为什么要学习集合?
1、数组的缺陷:
(1)数组中只能存储相同类型的数据。 (2)数组的长度固定不变,不能很好的解决元素数量动态变化的问题。 (3)虽然可以通过数组名.length获取数组的长度,但却无法直接获取 其中真正存储的元素的个数; (4)数组采取的是在内存中分配连续空间的方式来存储数据,虽然可以 通过下标快速获取元素,但是反过来,要想通过某个元素的信息来查找这个元素 时却比较麻烦,需要逐个遍历,效率低下。 (5)无法通过更复杂、方便的方式来存储数据.... 2、针对数组的这些缺陷,Java 提供了比数组更灵活、更实用的“集合框架”,可大大 提高软件的开发效率,并且不同的集合可适用于不同的场合。
二、什么是集合?
1、与变量、数组一样,集合也是存储数据的一种容器。 2、它由一组接口和类组成,位于java.util包中。 3、它的关系结构如下: 虚线框表示接口或抽象类,实线框表示实现类,粗实线框表示常用的实现类。虚线和空 心箭头表示实现关系,虚线和实心箭头表示依赖关系(即线连接的类中使用了箭头所指向的类) JavaUML图解:https://www.cnblogs.com/shamao/p/10875550.html
三、list接口:有序 & 不唯一
(1)ArraysList:
①和数组采用相同的存储方式,在内存中开辟连续的空间,并且实 现了长度可变的数组,也称为动态数组。 ②与数组的不同的是:数组只能存储相同类型的元素,但 ArraysList可以存储任何类型的元素,并且会把所有元素都转换成 Object类型(本质上仍是相同数据类型)。 ③因其内存空间连续,在增加和删除非尾部元素时会造成其它元素 的移动,因此(“增删改”)效率较低。但 适用于遍历和随机访问元 素 (即“查”)。(2)LinkedList:
①采用链表式的存储方式,适用于插入和删除元素,不适用于查找 元素。与ArraysList互补。
四、set:无序&唯一
①它的查找效率更高
注:set没有get方法
五、Iterator:对集合进行迭代遍历
(1)使用iterator()方法获取Iterator对象:Iterator iterator=****.iterator(); (2)hasNext():判断是否存在下一个可迭代的元素,有则返回true; (3)next():获取要访问的下一个元素;
六、Map:
①存储K键-V值组合; ②K键是一个set集合,不要求有序,不可重复; ③value不要求序但可重复; Map七.Collections 类>map=newHashMap<>();//复合 结构,可存放如某人的通话记录类的数据。
(1)排序: //comparable:可比较的 若要对一个类的对象进行排序,要先让这个类实现comparable接口,再 调用方法: intcomparaTo(Objecto): this>o 返回1;thisCollections类:
一、Collections类,类似于Arrays类,其中提供了很多用于操作集合 的、静态的方法。泛型:二、如果要实现一个类的对象之间比较大小,则该类必须要实现 Comparable接口,并根据需要重写其中的compareTo()方法。用来比较两个对象,如果o1小于o2,返回负数;等于o2,返回0;大 于o2返回正数 intcompare(To1,To2);https://www.zhihu.com/tardis/error?status=500 https://www.cnblogs.com/coprince/p/8603492.html https://www.jianshu.com/p/986f732ed2f1 泛型:所谓“泛型”,就是“宽泛的数据类型”,任意的数据类型。 它的本质是参数化类型,也就是说所操作的数据类型被指定为一个 参数,使代码可以应用于多种类型。即:将对象的类型作为参数,指定 到其他类或者方法上,从而保证类型转换的安全性和稳定性,这就是泛 型。 类型参数必须是一个合法的标识符,习惯上使用单个大写字母,通常情况 下,K 表示键,V 表示值,E 表示异常或错误,T 表示一般意义上的数据类型。 注意: 1.泛型参数只能使用引用类型变量来充当,不能使用基本数据类型 2.集合中,如果没使用泛型,则默认为Object类型 3.如果集合中使用泛型,则集合的相关属性、方法中,凡是使用到类 或接口泛型参数的地方,都调整为具体的泛型类型。数组与集合的异同
数组和集合的主要区别包括以下几个方面: 1. 数组可以存储基本数据类型和对象,集合只能存储对象(可以以包装类 的形式存储基本数据类型); 2. 数组的长度固定,而集合的长度是可变的; 3. 定义数组时必须指定数组元素类型,集合则是默认其中的所有元素类型 都是Object; 4. 无法直接获取数组中实际存储的元素个数,但集合可以通过size()方法 直接获取集合中实际存储的元素个数; 5. 数组只采用分配连续空间的方式存储数据,而集合有多种实现方式和不 同的适用场合; 6. 集合以接口和类的形式存在,具有封闭、继承、多态等类的特性,通过 简单的方法和属性调用即可实现各种复杂操作,大大提高了开发效率; 7. JDK中有一个Arrays类,专门用来操作数组,它提供一系列静态方法实 现以数组的搜索、排序、比较、填充等操作; 8. JDK中也有一个Collection类,专门用来操作集合,它也提供了一系列 的静态方法实现对集合的搜索、复制、排序、线程安全化等操作。ArrayList其它方法
ArrayList和LinkedList有什么区别?
ArrayList和LinkedList有什么区别? 相同点: 都实现了List接口 非线程安全的 集合中的元素都是有序的 不同点: 1. 底层数据结构 ArrayList 底层采用数组来存储元素的。 LinkedList 底层采用双向链表来存储元素的。 2. add(E e):尾部添加元素 ArrayList 内部是采用数组结构,若数组的容量足够大的时候,向尾部追加元素是 相当快的,只需数组[size+1] = e;即可,但是当数组满的时候,需要对数组进行扩 容,会生成一个新的数组,新的数组大小为原数组大小的1.5倍,然后将老的数据复制 到新的数组中,这个需要一定的时间,如果扩容之后只新增了一个元素,此时可能会造 成一些空间的浪费。 而LinkedList内部采用双向链表的结构存放数据,所以追加元素的时候,只需要将 最后一个元素next指针指向新的元素就可以了,非常的快。 结论:add(E e)向尾部追加元素LinkedList更快一些。 3. add(int index, E element):指定的位置插入元素 ArrayList:index位置插入元素的时候,需要将index位置后面的元素后移,若数 组已满,涉及到数组的扩容和复制,相对来说效率不是特别的高。 LinkedList:需沿着链表找到index位置的元素,然后改变一下指针的指向就可以 了,主要耗时在index位置的查找上。 结论:add(int index, E element)他们的效率差不多。 4. get(int index):获取指定位置的元素 ArrayList内部通过数组定义,非常快。 而LinkedList内部需要沿着链表查找,会慢一些,看一下LinkedList 的get(index)源 码public E get(int index) { return node(index).item; }Node结论:get(index)随机访问ArrayList更快。 5. remove(int index):随机删除指定位置元素 ArrayList:涉及到数组内元素的移动,将index位置后面的元素向前移动。 LinkedList:先找到指定位置的元素,然后调整一下指针的指向就可以了。 结论:remove(index)随机删除指定位置元素LinkedList更快。 6. remove(Object o):删除指定的元素 ArrayList:先按顺序找到这个元素的位置,然后将位置后面的所有元素前移,内部涉 及到数组元素的移动。 LinkedList:先按顺序找到这个元素的位置,然后调整一下指针的指向就可以了,更快 一些。 结论:remove(o) LinkedList更快。 7. int indexOf(Object o):获取元素的位置 ArrayList:按序遍历查找。 LinkedList:按序遍历查找。 结论:2则都需要遍历,效率差不多。 8. set(int index, E element):替换指定位置的元素 ArrayList:数组[index] = elelement 就可以了,非常的快。 LinkedList:需要先找到inde位置的元素,然后调整一下指针的指向。 结论:替换元素ArrayList更快。 使用场景 根据它们的优缺点,可以知道,ArrayList适用于频繁查询和获取数据;而LinkedList适合 频繁地增加或删除数据的场景。 总结 大家已经注意到了,这道题目主要考察的是2个集合内部的数据结构,一个是数组,一 个是双向链表,2种数据结构的特点搞清楚了,那么问题就很容易了。数组通过下标访问元 素是非常快的,但是插入或者删除元素会涉及到后面元素的移动,所以效率会慢一些。而链 表中插入和删除只需要调整一下指针的指向就行了,所以非常快node(int index) { //判断index是否位于集合的前半部分,如果在前半部分,从头向后找,如果在后半部分, 从最后向前找 if (index < (size >> 1)) { Node x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { Node x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; } } 集合的容量
1、List 元素是有序的、可重复 ArrayList、Vector默认初始容量为10 ArrayList :线程不安全,查询速度快 底层数据结构是数组结构 扩容增量:原容量的 0.5倍+1个 如 ArrayList的容量为10,一次扩容后是容量为15+1=16 LlinkedList: 是一个双向链表,没有初始化大小,也没有扩容的机制,就是 一直在前面或者后面新增就好。 Vector :线程安全,但速度慢 底层数据结构是数组结构 加载因子为1:即当元素个数超过容量长度时,进行扩容 扩容增量:原容量的 1倍 如 Vector的容量为10,一次扩容后是容量为20 2、Set(集) 元素无序的、不可重复 HashSet :线程不安全,存取速度快 底层实现是一个HashMap(保存数据),实现Set接口 默认初始容量为16(为何是16,见下方对HashMap的描述) 加载因子为0.75:即当元素个数超过容量长度的0.75倍时, 进行扩容 扩容增量:原容量的 1 倍 如 HashSet的容量为16,一次扩容后是容量为32 3、Map是一个双列集合 HashMap:默认初始容量为16 (为何是16:16==2^4,可以提高查询效率) 加载因子为0.75:即当元素个数超过容量长度的0.75倍时, 进行扩容 扩容增量:原容量的 1 倍 如 HashSet的容量为16,一次扩容后是容量为32 4、一个问题:ArrayList list = new ArrayList(20);中的list扩充几次? 答:0次。 解析: ArrayList list=new ArrayList(); 这种是默认创建大小 为10的数组,每次扩容大小为1.5倍。 ArrayList list=new ArrayList(20); 这种是指定数 组大小的创建,没有扩充。



