集合框架的概述
集合、數(shù)組都是對(duì)多個(gè)數(shù)據(jù)進(jìn)行存儲(chǔ)操作的結(jié)構(gòu),簡(jiǎn)稱Java容器。
說(shuō)明
此時(shí)的存儲(chǔ),主要指的是內(nèi)存層面的存儲(chǔ),不涉及到持久化的存儲(chǔ)(.txt,.jpg,.avi,數(shù)據(jù)庫(kù)中)
背景
1. 數(shù)組在存儲(chǔ)多個(gè)數(shù)據(jù)方面的特點(diǎn):
? ? ? ?> 一旦初始化以后,其長(zhǎng)度就確定了。
? ? ? ?> 數(shù)組一旦定義好,其元素的類型也就確定了。我們也就只能操作指定類型的數(shù)據(jù)了。
? ? ? ? ? 比如:String[] arr; int[] arr1; Object[] arr2;
2. 數(shù)組在存儲(chǔ)多個(gè)數(shù)據(jù)方面的缺點(diǎn):
? ? ? ?> 一旦初始化以后,其長(zhǎng)度就不可修改。
? ? ? ?> 數(shù)組中提供的方法非常有限,對(duì)于添加、刪除、插入數(shù)據(jù)等操作,非常不便,同時(shí)效率不高。
? ? ? ?> 獲取數(shù)組中實(shí)際元素的個(gè)數(shù)的需求,數(shù)組沒(méi)有現(xiàn)成的屬性或方法可用
? ? ? ?> 數(shù)組存儲(chǔ)數(shù)據(jù)的特點(diǎn):有序、可重復(fù)。對(duì)于無(wú)序、不可重復(fù)的需求,不能滿足。
集合使用場(chǎng)景

集合框架

*? ? ? |----Collection接口:?jiǎn)瘟屑?,用?lái)存儲(chǔ)一個(gè)一個(gè)的對(duì)象
*? ? ? ? ? |----List接口:存儲(chǔ)有序的、可重復(fù)的數(shù)據(jù)。? ????--> 又稱為“動(dòng)態(tài)”數(shù)組 (長(zhǎng)度可修改)
*? ? ? ? ? ? ? |----ArrayList、LinkedList、Vector
*? ? ? ? ? |----Set接口:存儲(chǔ)無(wú)序的、不可重復(fù)的數(shù)據(jù)? ? ? -->類似于高中講的“集合”
*? ? ? ? ? ? ? |----HashSet、LinkedHashSet、TreeSet
? ?Collection接口繼承樹(shù)

Collection接口中的方法的使用
實(shí)例化
(Collection是抽象方法,不能實(shí)例化,只能實(shí)例化它的子類)
Collection coll =new ArrayList();
方法
1. add(Object e):
????????將元素e添加到集合coll中
????????coll.add("AA");
? ? ? ? coll.add(123);????//自動(dòng)裝箱
????????Person p = new Person("Jerry",20);
? ??????coll.add(p);
? ? ? ? coll.add(new Person("Jerry",20));
2. size():
????????獲取添加的元素的個(gè)數(shù)
????????System.out.println(coll.size());????// 5(上面的coll長(zhǎng)度)
3. addAll(Collection coll1):
????????將coll1集合中的元素添加到當(dāng)前的集合中
????????Collection coll1 =new ArrayList();
????????coll1.add(456);
????????coll1.add("CC");
????????coll.addAll(coll1);
????????System.out.println(coll.size());????//7
4. clear():
????????清空集合元素
????????coll.clear();
5. isEmpty():
????????判斷當(dāng)前集合是否為空
????????System.out.println(coll.isEmpty());? ? // true
6. contains(Object obj):
????????判斷當(dāng)前集合中是否包含obj
? ? ? ? 我們?cè)谂袛鄷r(shí)會(huì)調(diào)用obj對(duì)象所在類的equals()。
? ? ? ? boolean contains = coll1.contains(456);? ? //true
? ? ? ? System.out.println(coll1.contains(new String("CC")));? ? //true
? ? ? ? coll1.add(new Person("Jerry",20)));
? ? ? ? System.out.println(coll1.contains(new Person("Jerry",20)));????//false
?????????(要變成true則重寫(xiě)toString方法,要比較的對(duì)象處于第幾個(gè)object,就調(diào)用多少個(gè)toString方法去對(duì)比)
7.containsAll(Collection coll1):
????????判斷形參coll2中的所有元素是否都存在于當(dāng)前集合中。
? ? ? ? Collection coll2 = Arrays.asList(123,4567);
? ? ? ? System.out.println(coll1.containsAll(coll2));? ? //false? (判斷coll1中是否包含123和4567,只要有一個(gè)不包含就返回false)
8.?remove(Object obj):
????????從當(dāng)前集合中移除obj元素。
????????Collection coll =new ArrayList();
????????coll.add(123);
? ??????coll.add(456);
????????coll.add(new Person("Jerry",20));
????????coll.add(new String("Tom"));
????????coll.add(false);
????????coll.remove(new String("Tom"));?
????????System.out.println(coll);? ? // [123, 456, Person{name='Jerry', age=20}, false]
9. removeAll(Collection coll1):
????????差集:從當(dāng)前集合中移除coll1中所有的元素。
????????Collection coll1 = Arrays.asList(123,4567);
????????coll.removeAll(coll1);
????????System.out.println(coll);? ? //[456, Person{name='Jerry', age=20}, false]
10. retainAll(Collection coll2):
????????交集:獲取當(dāng)前集合和coll2集合的交集,并返回給當(dāng)前集合
? ? ? ? Collection coll2 = Arrays.asList(123,456,789);
? ? ? ? coll.retainAll(coll2);
? ? ? ? System.out.println(coll);? ? // 456
11. equals(Object obj):
????????要想返回true,需要當(dāng)前集合和形參集合的元素都相同,與順序無(wú)關(guān)
12. hashCode():
? ??????返回當(dāng)前對(duì)象的哈希值
和數(shù)組之間相互轉(zhuǎn)換
1. 集合 --->數(shù)組:
? ??toArray()
? ? Object[] arr = coll.toArray();
2. 數(shù)組 --->集合:
????調(diào)用Arrays類的靜態(tài)方法asList()
????List list = Arrays.asList(new String[]{"AA", "BB", "CC"});
????System.out.println(list);? ? // [AA,BB,CC]
? ? 注意如下寫(xiě)法只能識(shí)別為一個(gè)元素:
? ??List arr1 = Arrays.asList(new int[]{123, 456});
? ? System.out.println(arr1.size());//1
? ? 應(yīng)改為以下寫(xiě)法:
????List arr2 = Arrays.asList(new Integer[]{123, 456});
????System.out.println(arr2.size());//2
iterator迭代器接口:
用于遍歷Collection集合元素。使用迭代器Iterator接口

內(nèi)部的方法
next():
方式一:
????????Collection coll =new ArrayList();
? ? ? ? coll.add(123);
? ? ? ? coll.add(new Person("Jerry",20));
? ? ? ? Iterator iterator = coll.iterator();
? ? ? ? System.out.println(iterator.next());? ? // 123????
? ? ? ? System.out.println(iterator.next());? ? //?Person{name='Jerry', age=20}
? ? ? ? System.out.println(iterator.next());? ? // 報(bào)異常:NoSuchElementException
方式二:
? ??????for(int i = 0;i < coll.size();i++){
? ? ? ? ? ? System.out.println(iterator.next());}
hasNext()?
判斷是否還有下一個(gè)元素
????????while(iterator.hasNext()){
? ? ????????????System.out.println(iterator.next());}?????//①指針下移? ②將下移以后集合位置上的元素返回
????????? 錯(cuò)誤寫(xiě)法一:
? ? ? ? 指針下移兩次,檢查第一個(gè),輸出第二個(gè)
? ??????Iterator iterator = coll.iterator();
? ? ? ? ? while((iterator.next()) != null){
? ? ? ? ? ? ? System.out.println(iterator.next());}
? ? ? ? ? 錯(cuò)誤寫(xiě)法二
? ??????集合對(duì)象每次調(diào)用iterator()方法都得到一個(gè)全新的迭代器對(duì)象,默認(rèn)游標(biāo)都在集合的第一個(gè)元素之前。
????????while (coll.iterator().hasNext()){
????????System.out.println(coll.iterator().next());}
remove()
內(nèi)部定義了remove(),可以在遍歷的時(shí)候,刪除集合中的元素。此方法不同于集合直接調(diào)用remove()
????????Iterator iterator = coll.iterator();
? ? ? ? ????????while (iterator.hasNext()){? ? //如果有下一個(gè)元素,則返回true
? ? ? ? ????????? ? Object obj = iterator.next();
? ? ????????? ? ? ? if("Tom".equals(obj)){? ? ? ? // 如果集合中找到Tom
? ? ? ? ? ? ????????? ? iterator.remove();}}? ? ? ? // 則移除
? ? ? ? iterator = coll.iterator();? ? // 遍歷集合,必須重新得到一個(gè)全新的迭代器對(duì)象(指針移到初始位置)
? ? ? ? while (iterator.hasNext()){
????????????????System.out.println(iterator.next());}}
?? 如果還未調(diào)用next()或在上一次調(diào)用 next 方法之后已經(jīng)調(diào)用了 remove 方法,再調(diào)用remove都會(huì)報(bào)IllegalStateException。
?? 集合對(duì)象每次調(diào)用iterator()方法都得到一個(gè)全新的迭代器對(duì)象
?? 默認(rèn)游標(biāo)都在集合的第一個(gè)元素之前。
Foreach
jdk 5.0 新增了foreach循環(huán),用于遍歷集合、數(shù)組,內(nèi)部仍然調(diào)用了迭代器。
格式:for(集合元素的類型 局部變量 : 集合對(duì)象)
????遍歷集合
????????for(Object obj : coll){
????????System.out.println(obj);}
? ? 遍歷數(shù)組
? ??????int[] arr =new int[]{1,2,3,4,5,6};
????????//for(數(shù)組元素的類型 局部變量 : 數(shù)組對(duì)象)
????????for(int i : arr){
????????System.out.println(i);}
??? 使用增強(qiáng)for循環(huán)賦值,不會(huì)改變arr的值,只是將arr的值賦給了i,i做了改變
????????for(String i : arr){
????????????i ="AA";}
????????for (String i : arr){
????????????System.out.println(i);}
Collection子接口
List接口
通常用來(lái)替代數(shù)組,List集合類中元素有序、且可重復(fù),集合中的每個(gè)元素都有其對(duì)應(yīng)的順序索引
List接口框架
? ? |----Collection接口:?jiǎn)瘟屑?,用?lái)存儲(chǔ)一個(gè)一個(gè)的對(duì)象
? ? ? ? ? |----List接口:存儲(chǔ)有序的、可重復(fù)的數(shù)據(jù)。? -->“動(dòng)態(tài)”數(shù)組,替換原有的數(shù)組
? ? ? ? ? ? ? ????|----ArrayList:作為L(zhǎng)ist接口的主要實(shí)現(xiàn)類;線程不安全的,效率高;底層使用Object[] elementData存儲(chǔ)
? ? ? ? ? ? ????? |----LinkedList:對(duì)于頻繁的插入、刪除操作,使用此類效率比ArrayList高;底層使用雙向鏈表存儲(chǔ)
? ? ? ? ? ? ????? |----Vector:作為L(zhǎng)ist接口的古老實(shí)現(xiàn)類;線程安全的,效率低;底層使用Object[] elementData存儲(chǔ)
源碼分析
ArrayList
????????jdk 7情況下
? ? ? ?ArrayList list = new ArrayList();//底層創(chuàng)建了長(zhǎng)度是10的Object[]數(shù)組elementData
? ? ? ?list.add(123);//elementData[0] = new Integer(123);
? ? ? ?...
? ? ? ?list.add(11);//如果此次的添加導(dǎo)致底層elementData數(shù)組容量不夠,則擴(kuò)容。
? ? ? ?默認(rèn)情況下,擴(kuò)容為原來(lái)的容量的1.5倍,同時(shí)需要將原有數(shù)組中的數(shù)據(jù)復(fù)制到新的數(shù)組中。
? ? ? ?結(jié)論:建議開(kāi)發(fā)中使用帶參的構(gòu)造器:ArrayList list = new ArrayList(int capacity)
????????jdk 8中ArrayList的變化:
? ? ? ?ArrayList list = new ArrayList();//底層Object[] elementData初始化為{}.并沒(méi)有創(chuàng)建長(zhǎng)度為10的數(shù)組
? ? ? ?list.add(123);//第一次調(diào)用add()時(shí),底層才創(chuàng)建了長(zhǎng)度10的數(shù)組,并將數(shù)據(jù)123添加到elementData[0]
? ? ? ?...
? ? ? ?后續(xù)的添加和擴(kuò)容操作與jdk 7 無(wú)異。
????小結(jié)
????????jdk7中的ArrayList的對(duì)象的創(chuàng)建類似于單例的餓漢式,而jdk8中的ArrayList的對(duì)象的創(chuàng)建類似于單例的懶漢式,延遲了數(shù)組的創(chuàng)建,節(jié)省內(nèi)存。
LinkedList
LinkedList list = new LinkedList(); 內(nèi)部聲明了Node類型的first和last屬性,默認(rèn)值為null
? ? ? ?list.add(123);//將123封裝到Node中,創(chuàng)建了Node對(duì)象。其中,Node定義為:體現(xiàn)了LinkedList的雙向鏈表的說(shuō)法
? ? ? ?private static class Node<E> {
????????????E item;
????????????Node<E> next;
????????????Node<E> prev;
? ? ? ?Node(Node<E> prev, E element, Node<E> next) {
????????????this.item = element;
????????????this.next = next;
????????????this.prev = prev; }}
Vector
????????jdk7和jdk8中通過(guò)Vector()構(gòu)造器創(chuàng)建對(duì)象時(shí),底層都創(chuàng)建了長(zhǎng)度為10的數(shù)組。
? ? ? ?在擴(kuò)容方面,默認(rèn)擴(kuò)容為原來(lái)的數(shù)組長(zhǎng)度的2倍。
方法的使用
ArrayList
void add(int index, Object ele):在index位置插入ele元素
boolean addAll(int index, Collection eles):從index位置開(kāi)始將eles中的所有元素添加進(jìn)來(lái)
Object get(int index):獲取指定index位置的元素
int indexOf(Object obj):返回obj在集合中首次出現(xiàn)的位置
int lastIndexOf(Object obj):返回obj在當(dāng)前集合中末次出現(xiàn)的位置
Object remove(int index):移除指定index位置的元素,并返回此元素
Object set(int index, Object ele):設(shè)置指定index位置的元素為ele
List subList(int fromIndex, int toIndex):返回從fromIndex到toIndex位置的子集合
總結(jié):常用方法
增:add(Object obj)
刪:remove(int index) / remove(Object obj)
改:set(int index, Object ele)
查:get(int index)
插:add(int index, Object ele)
長(zhǎng)度:size()
遍歷: ① Iterator迭代器方式
????????????② 增強(qiáng)for循環(huán)
????????? ? ③ 普通的循環(huán)