数组千千万,集合是真理
我们在代码中常见的数据保存形式一般就是两种—>数组与集合;数组和集合的最大的区别在于查询和扩展,一般情况下,在数据确定的情况下,我们采用数组的形式会更便于我们查询,而在数据长度不确定的情况下,我相对更推荐集合。
集合产生的原因:
一方面,面向对 象语言对事物的体现 都是以对象的形式,为了方便对多 个对象的操作,就要对对象进行存储。
另-方面,使用Array存储对 象方面具有一些弊端,大小不能动态改变,而Java 集合就像一 种容器,可以动态地把多 个对象的引用放入容器中。所以,Java集合类可以用于存储数量不等的多个对象,还可用于保存具有映射关系的关联数组。
数组与集合的扩容
数组的扩容
我们都知道的是数组在一旦确定下来的时候我们是无法对数组的长度进行改变的,所以对数组进行扩容就只能通过创建一个新的更长的数组来将原来的数组长度给复制过去才可以。这一段我在数组的时候就有所研究了,所以直接给大家上一段代码帮助理解:
int[] arr1 = new int[3]; arr1[0]=1; arr1[1]=2; arr1[2]=3; //打印传入的数据 System.out.println("arr1:"); for (int i = 0; i < arr1.length; i++) { System.out.print(arr1[i]+","); } System.out.println(); //复制值 int[] arr2 = new int[arr1.length*2]; for (int i = 0; i < arr1.length; i++) { arr2[i] = arr1[i]; } arr2[arr1.length] = 4; //展示复制后的数组 for (int i = 0; i < arr2.length; i++) { System.out.print(arr2[i]+","); }
集合的扩容
集合的扩容相对来说就比数组要简单很多了,因为集合本身的特点就是:提供一种存储可变的存储模型,存储数据容量可以随时改变。下面以ArrayList举例叭:
List<String> list = new ArrayList<String>(); list.add("pier"); list.add("is"); list.add("大聪明"); for (int i = 0; i < list.size(); i++) { System.out.print(list.get(i)+" "); }
集合细解
集合的大概框架
集合的大概主要分为两类:Collection集合与Map集合,他们都是用来存储数据的,但是最主要的使用区别是,Collection集合存储的更多是元素集合,他们内部的存储数据是有序的,数据是可以重复的,而Map集合存储的更多的是键值对形式的数据,它内部的数据是无序的,并且内部的‘键值’是不可重复的。
下面给大家分享一个集合的菜鸟编程图叭:
由上面图我们可以看到的东西分为下面三类框架:
接口:是代表集合的抽象数据类型。例如 Collection、List、Set、Map 等。之所以定义多个接口,是为了以不同的方式操作集合对象
实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap。
算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现。
Collection集合类架构
Collection集合分为三大类:List、Set、Queue,再下面是一些抽象类,最后是具体实现类,常用的有 ArrayList、LinkedList、HashSet、LinkedHashSet等等接口。
上面一个简单对话,就把我们的数据的添加以及简单的扩容机制讲解清楚了,下面我们一起看看ArrayList的源码叭:
/** *将指定的元素追加到此列表的末尾。 *要附加到此列表的@param e元素 *@return{@code true}(由{@link Collection#add}指定) */ public boolean add(E e) { modCount++; add(e, elementData, size); return true; } //这是add(E e)的实现代码 /** *这个助手方法从add(E)to keep方法中分离出来 *字节码大小小于35(默认值为-XX:MaxInlineSize), *这有助于在C1编译循环中调用add(E)。 */ private void add(E e, Object[] elementData, int s) { if (s == elementData.length) elementData = grow();//这里的grow就是我们下一段要讲的扩容机制 elementData[s] = e; size = s + 1; } /** *将指定的元素追加到此列表的末尾。 * *要附加到此列表的@param e元素 *@return{@code true}(由{@link Collection#add}指定) * /** *将指定的元素插入此文件中的指定位置 *名单。移动当前处于该位置的元件(如果有),并 *右侧的任何后续元素(将一个元素添加到其索引中)。 * *@param index将插入指定元素的索引 *@param元素要插入的元素 *@throws IndexOutOfBoundsException{@inheritDoc} */ public void add(int index, E element) { rangeCheckForAdd(index); modCount++; final int s; Object[] elementData; if ((s = size) == (elementData = this.elementData).length) elementData = grow(); System.arraycopy(elementData, index, elementData, index + 1, s - index); elementData[index] = element; size = s + 1; }
ps:LinkedHashSet:他的注意点和HashSet大致相同,唯一需要重点注意的是他们俩的使用场景,待会将TreeSet和他们量放一起说。