集合框架的概述
集合聚请、數(shù)組都是對(duì)多個(gè)數(shù)據(jù)進(jìn)行存儲(chǔ)操作的結(jié)構(gòu)汁果,簡稱Java容器驾中。
說明
此時(shí)的存儲(chǔ),主要指的是內(nèi)存層面的存儲(chǔ)分衫,不涉及到持久化的存儲(chǔ)(.txt,.jpg,.avi场刑,數(shù)據(jù)庫中)
背景
1. 數(shù)組在存儲(chǔ)多個(gè)數(shù)據(jù)方面的特點(diǎn):
? ? ? ?> 一旦初始化以后,其長度就確定了蚪战。
? ? ? ?> 數(shù)組一旦定義好牵现,其元素的類型也就確定了。我們也就只能操作指定類型的數(shù)據(jù)了邀桑。
? ? ? ? ? 比如:String[] arr; int[] arr1; Object[] arr2;
2. 數(shù)組在存儲(chǔ)多個(gè)數(shù)據(jù)方面的缺點(diǎn):
? ? ? ?> 一旦初始化以后瞎疼,其長度就不可修改。
? ? ? ?> 數(shù)組中提供的方法非常有限壁畸,對(duì)于添加贼急、刪除、插入數(shù)據(jù)等操作瓤摧,非常不便竿裂,同時(shí)效率不高。
? ? ? ?> 獲取數(shù)組中實(shí)際元素的個(gè)數(shù)的需求照弥,數(shù)組沒有現(xiàn)成的屬性或方法可用
? ? ? ?> 數(shù)組存儲(chǔ)數(shù)據(jù)的特點(diǎn):有序腻异、可重復(fù)。對(duì)于無序这揣、不可重復(fù)的需求悔常,不能滿足影斑。
集合使用場(chǎng)景
集合框架
*? ? ? |----Collection接口:單列集合,用來存儲(chǔ)一個(gè)一個(gè)的對(duì)象
*? ? ? ? ? |----List接口:存儲(chǔ)有序的机打、可重復(fù)的數(shù)據(jù)矫户。? ????--> 又稱為“動(dòng)態(tài)”數(shù)組 (長度可修改)
*? ? ? ? ? ? ? |----ArrayList、LinkedList残邀、Vector
*? ? ? ? ? |----Set接口:存儲(chǔ)無序的皆辽、不可重復(fù)的數(shù)據(jù)? ? ? -->類似于高中講的“集合”
*? ? ? ? ? ? ? |----HashSet、LinkedHashSet芥挣、TreeSet
? ?Collection接口繼承樹
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長度)
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則重寫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)前集合和形參集合的元素都相同畅厢,與順序無關(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]
? ? 注意如下寫法只能識(shí)別為一個(gè)元素:
? ??List arr1 = Arrays.asList(new int[]{123, 456});
? ? System.out.println(arr1.size());//1
? ? 應(yīng)改為以下寫法:
????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ò)誤寫法一:
? ? ? ? 指針下移兩次氮昧,檢查第一個(gè)框杜,輸出第二個(gè)
? ??????Iterator iterator = coll.iterator();
? ? ? ? ? while((iterator.next()) != null){
? ? ? ? ? ? ? System.out.println(iterator.next());}
? ? ? ? ? 錯(cuò)誤寫法二
? ??????集合對(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接口
通常用來替代數(shù)組,List集合類中元素有序槽驶、且可重復(fù)责嚷,集合中的每個(gè)元素都有其對(duì)應(yīng)的順序索引
List接口框架
? ? |----Collection接口:單列集合,用來存儲(chǔ)一個(gè)一個(gè)的對(duì)象
? ? ? ? ? |----List接口:存儲(chǔ)有序的掂铐、可重復(fù)的數(shù)據(jù)罕拂。? -->“動(dòng)態(tài)”數(shù)組,替換原有的數(shù)組
? ? ? ? ? ? ? ????|----ArrayList:作為List接口的主要實(shí)現(xiàn)類;線程不安全的全陨,效率高聂受;底層使用Object[] elementData存儲(chǔ)
? ? ? ? ? ? ????? |----LinkedList:對(duì)于頻繁的插入、刪除操作烤镐,使用此類效率比ArrayList高蛋济;底層使用雙向鏈表存儲(chǔ)
? ? ? ? ? ? ????? |----Vector:作為List接口的古老實(shí)現(xiàn)類;線程安全的炮叶,效率低碗旅;底層使用Object[] elementData存儲(chǔ)
源碼分析
ArrayList
????????jdk 7情況下
? ? ? ?ArrayList list = new ArrayList();//底層創(chuàng)建了長度是10的Object[]數(shù)組elementData
? ? ? ?list.add(123);//elementData[0] = new Integer(123);
? ? ? ?...
? ? ? ?list.add(11);//如果此次的添加導(dǎo)致底層elementData數(shù)組容量不夠,則擴(kuò)容镜悉。
? ? ? ?默認(rèn)情況下祟辟,擴(kuò)容為原來的容量的1.5倍,同時(shí)需要將原有數(shù)組中的數(shù)據(jù)復(fù)制到新的數(shù)組中侣肄。
? ? ? ?結(jié)論:建議開發(fā)中使用帶參的構(gòu)造器:ArrayList list = new ArrayList(int capacity)
????????jdk 8中ArrayList的變化:
? ? ? ?ArrayList list = new ArrayList();//底層Object[] elementData初始化為{}.并沒有創(chuàng)建長度為10的數(shù)組
? ? ? ?list.add(123);//第一次調(diào)用add()時(shí)旧困,底層才創(chuàng)建了長度10的數(shù)組,并將數(shù)據(jù)123添加到elementData[0]
? ? ? ?...
? ? ? ?后續(xù)的添加和擴(kuò)容操作與jdk 7 無異稼锅。
????小結(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的雙向鏈表的說法
? ? ? ?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中通過Vector()構(gòu)造器創(chuàng)建對(duì)象時(shí)哮肚,底層都創(chuàng)建了長度為10的數(shù)組登夫。
? ? ? ?在擴(kuò)容方面,默認(rèn)擴(kuò)容為原來的數(shù)組長度的2倍允趟。
方法的使用
ArrayList
void add(int index, Object ele):在index位置插入ele元素
boolean addAll(int index, Collection eles):從index位置開始將eles中的所有元素添加進(jìn)來
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)
長度:size()
遍歷: ① Iterator迭代器方式
????????????② 增強(qiáng)for循環(huán)
????????? ? ③ 普通的循環(huán)