今日任務(wù)
1、集合框架繼承體系(理解)
2、Collection接口介紹(掌握常用Collection方法)
3、迭代器(掌握)
4、集合的細(xì)節(jié)
5、集合使用的步驟
1、集合框架的繼承體系
集合是用來(lái)存儲(chǔ)數(shù)據(jù)的一類(lèi)容器,但是在使用集合存儲(chǔ)數(shù)據(jù)時(shí),也會(huì)有不同的存儲(chǔ)需求。例:存儲(chǔ)的數(shù)據(jù)不能有重復(fù)的、存儲(chǔ)的數(shù)據(jù)可以自動(dòng)排序、存儲(chǔ)的數(shù)據(jù)無(wú)序。針對(duì)不同的存儲(chǔ)需求,java設(shè)計(jì)了存儲(chǔ)不同需求的集合對(duì)象。這些針對(duì)不同需求的集合對(duì)象,雖然存儲(chǔ)方法式不同,但是都具有共性的功能:比如:增、刪、改、查(CRUD create read update delete)等操作。所以我們把共性的操作向上抽取,最終形成了一個(gè)集合框架的繼承體系結(jié)構(gòu)。
既然有上述的共性的規(guī)律,于是Java就把這些最基本的規(guī)律抽取到了一個(gè)接口中。其中一個(gè)頂級(jí)接口就是:Collection接口。
在集合框架體系中用接口來(lái)定義所有集合操作的共性規(guī)則。
集合體系框架從JDK1.2才開(kāi)始存在。早期有集合,但是它們沒(méi)有形成一個(gè)體系。
集合框架的繼承體系如下圖所示:
說(shuō)明:
1)Collection是這個(gè)體系的頂級(jí)接口;
2)Collection中定義了所有集合子類(lèi)的共性操作;
3)我們先從Collection接口開(kāi)始學(xué)習(xí),將Collection中的函數(shù)學(xué)完之后,實(shí)現(xiàn)類(lèi)都可以直接使用,最后我們?cè)谌W(xué)習(xí)子類(lèi)特有的函數(shù)就可以了;
4)通過(guò)查閱API得知Collection、List、Set接口下面不是只有如上圖所示的子類(lèi)或者子接口,但是我們?cè)陂_(kāi)發(fā)中主要使用這些集合;
2、集合Collection接口
2.1、Collection接口介紹
Collection接口:它是集合的最頂層接口,它中規(guī)定了所有集合中的最基本的操作規(guī)律。而Java中提供的所有集合容器都保存在java.util包下。
Collection接口是集合的頂層接口,它下面有子接口或者間接的實(shí)現(xiàn)類(lèi),而具體的實(shí)現(xiàn)類(lèi)中有些可以保存重復(fù)元素,有些不能保存重復(fù)元素,有些可以保證數(shù)據(jù)有序,一些則無(wú)序。
說(shuō)明:在學(xué)習(xí)集合框架的時(shí)候,遇到的所有E類(lèi)型,全部理解成Object類(lèi)型。
2.2、Collection中的方法介紹
2.2.1、添加方法
說(shuō)明:把指定的引用類(lèi)型數(shù)據(jù),添加到集合中。添加成功則返回true。
我們知道Collection是接口,它不能new對(duì)象。而Collection中定義的是所有集合共性的操作規(guī)律。那么我們就可以隨便找個(gè)Collection的實(shí)現(xiàn)類(lèi),例如ArrayList類(lèi)。這樣就可以使用多態(tài)的方式來(lái)操作集合。
代碼舉例:Collection coll=new ArrayList();//這里發(fā)生多態(tài)
步驟和分析:
1)使用new關(guān)鍵字創(chuàng)建集合類(lèi)ArrayList的對(duì)象,對(duì)象的類(lèi)型是接口Collection;
2)使用集合對(duì)象coll調(diào)用add()函數(shù)給集合中添加不同的數(shù)據(jù);
package cn.xuexi.demo1;
import java.util.ArrayList;
import java.util.Collection;
import cn.xuexi.sh.demo.Student;
/*
* Collection接口中add方法的演示
*/
public class CollectionAddDemo {
public static void main(String[] args) {
/*
*由于Collection是接口,所以不能創(chuàng)建Collection接口的對(duì)象,
*但是我們可以使用new關(guān)鍵字創(chuàng)建Collection接口下面的任意一個(gè)類(lèi)的對(duì)象,然后對(duì)象類(lèi)型變?yōu)镃ollection
*/
Collection coll=new ArrayList();//這里發(fā)生多態(tài)了
//使用coll對(duì)象調(diào)用add函數(shù)向集合中添加引用類(lèi)型數(shù)據(jù)
coll.add("aaaa");
//創(chuàng)建學(xué)生對(duì)象
Student s =new Student("張三",19);
//將自定義類(lèi)的對(duì)象添加到集合中
coll.add(s);
/*
*在集合中是否可以存儲(chǔ)基本數(shù)據(jù)類(lèi)型?
*正常情況是不可以的,但是從jdk5之后,有了自動(dòng)裝箱和拆箱的功能
*如果使用集合添加基本數(shù)據(jù)類(lèi)型,實(shí)則jvm是把基本數(shù)據(jù)類(lèi)型包裝成了對(duì)應(yīng)的包裝類(lèi)對(duì)象并存儲(chǔ)到集合中了
*/
//Integer valueOf = Integer.valueOf(123);
coll.add(123);//這里相當(dāng)于coll.add(Integer.valueOf(123));
//Boolean valueOf =Boolean.valueOf(true);
coll.add(**true**);//這里相當(dāng)于coll.add(Boolean.valueOf(true));
//輸出集合中的數(shù)據(jù)
System.*out*.println(coll);
}
}
說(shuō)明:
1)add函數(shù)可以把一個(gè)對(duì)象保存在集合中,但是這個(gè)函數(shù)有返回值boolean,返回的結(jié)果是告訴我們是否給集合中添加成功。添加成功則返回true。
2)能否給集合中保存基本類(lèi)型數(shù)據(jù)?
嚴(yán)格意義上講是不可以的,因?yàn)榧现兄荒鼙4嬉妙?lèi)型數(shù)據(jù),而基本類(lèi)型數(shù)據(jù)不屬于引用類(lèi)型數(shù)據(jù),即不屬于對(duì)象,但是在jdk5之后,基本數(shù)據(jù)類(lèi)型有自動(dòng)裝箱和拆箱的機(jī)制,因此我們也可以直接把基本類(lèi)型的數(shù)據(jù)保存到集合中。
可是集合中存儲(chǔ)的根本不是基本類(lèi)型的數(shù)據(jù),而是基本類(lèi)型數(shù)據(jù)對(duì)應(yīng)的包裝類(lèi)型的對(duì)象。
如:coll.add(100);//此代碼存在裝箱coll.add(Integer.valueOf(100));
2.2.2、刪除方法
步驟:
1)創(chuàng)建集合對(duì)象coll;
2)使用集合對(duì)象coll調(diào)用add()函數(shù)向集合中添加數(shù)據(jù);
3)輸出集合中的數(shù)據(jù);
4)使用集合對(duì)象coll調(diào)用remove()函數(shù)刪除指定的數(shù)據(jù),并使用布爾類(lèi)型的數(shù)據(jù)接收刪除返回值boo;
5)輸出返回值boo和刪除后的數(shù)據(jù)coll;
根據(jù)指定的元素,刪除集合中對(duì)應(yīng)的元素。刪除成功則返回true,否則返回false。
package cn.xuexi.demo1;
import java.util.ArrayList;
import java.util.Collection;
/*
* Collection接口中的刪除方法remove演示
*/
public class Collection RemoveDemo {
public static void main(String[] args) {
//創(chuàng)建集合類(lèi)對(duì)象
Collection coll=**new** ArrayList();
//使用集合對(duì)象coll給集合中添加數(shù)據(jù)
coll.add("abc");
coll.add("aaa");
coll.add("ddd");
coll.add("aaa");
coll.add("yyy");
//輸出集合中的數(shù)據(jù)
System.*out*.println(coll);
//使用集合對(duì)象coll調(diào)用remove刪除函數(shù)
boolean boo = coll.remove("aaa");
// boolean boo1 = coll.remove("aaa");
// boolean boo = coll.remove("xxx");//由于要?jiǎng)h除的元素不在集合中,所以返回結(jié)果是false
System.out.println(boo);
// System.out.println(boo1);
System.out.println(coll);
}
}
清空集合中所有的存儲(chǔ)的元素。
步驟:
1)使用集合對(duì)象coll調(diào)用clear()函數(shù)清空集合中的所有元素;
2)輸出清空后的集合;
說(shuō)明:
使用clear()函數(shù)清空集合中的元素后,集合容器依然存在,所以還可以繼續(xù)向集合中添加元素。
問(wèn)題:
把集合設(shè)為null和使用集合對(duì)象中的clear()方法有什么區(qū)別?
集合=null 表示這個(gè)集合對(duì)象沒(méi)有任何引用了。如:coll=null,那么堆中對(duì)象的空間就沒(méi)有任何指向他了,而棧中的coll引用變量空間是一個(gè)空指向,所以這里會(huì)報(bào)空指針異常。
集合.clear() 表示集合中存儲(chǔ)的元素全部清空,但是集合對(duì)象還存在。
2.2.3、判斷方法
boolean contains(Object obj)函數(shù)表示判斷集合中是否存在指定的元素。
如果有指定的元素,則返回true,沒(méi)有則返回false。
boolean isEmpty()判斷集合是否為空。集合中沒(méi)有存儲(chǔ)任何元素表示為空。
注意:
1)這個(gè)函數(shù)不是集合引用是否為null,而是判斷集合中是否有元素;
2)如果集合中有元素返回false,集合中不包含元素則返回true。
步驟:
1)創(chuàng)建集合對(duì)象coll;
2)使用集合對(duì)象coll調(diào)用add()函數(shù)向集合中添加數(shù)據(jù);
3)使用集合對(duì)象coll調(diào)用contains()函數(shù)判斷集合某個(gè)數(shù)據(jù)是否在集合中,如果有返回true,否則返回false;
4)使用集合對(duì)象coll調(diào)用clear()函數(shù)清除集合中的所有數(shù)據(jù);
5)使用集合對(duì)象coll調(diào)用isEmpty()函數(shù)判斷集合中元素是否有數(shù)據(jù),如果有數(shù)據(jù)則返回false,沒(méi)有數(shù)據(jù)則返回true;
package cn.xuexi.demo1;
import java.util.ArrayList;
import java.util.Collection;
/*
*判斷方法
*/
public class Collection ContainsAndIsEmptyDemo {
public static void main(String[] args) {
//創(chuàng)建集合對(duì)象
Collection coll=new ArrayList();
//給集合添加數(shù)據(jù)
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
coll.add("ddd");
//使用Collection接口中的contains()函數(shù)判斷某個(gè)對(duì)象是否在集合中
//如果有,則返回true,如果沒(méi)有,則返回false
boolean boo = coll.contains("aaa");
System.out.println(boo);
//輸出集合數(shù)據(jù)
System.out.println(coll);
//判斷集合中是否有數(shù)據(jù),如果有數(shù)據(jù)則返回false,沒(méi)有數(shù)據(jù)則返回true
boolean boo1 = coll.isEmpty();
System.out.println(boo1);
//清空集合中的數(shù)據(jù)
coll.clear();
boolean boo2 = coll.isEmpty();
System.out.println(boo2);
}
}
2.2.4、Collection接口中帶All的方法
boolean addAll(Collectionc)表示把c集合中的元素全部添加到當(dāng)前調(diào)用這個(gè)方法的集合中。
分析和步驟:
1)使用new關(guān)鍵字創(chuàng)建集合類(lèi)ArrayList的兩個(gè)對(duì)象coll和coll2,兩個(gè)對(duì)象的類(lèi)型是接口Collection;
2)使用coll和coll2對(duì)象分別調(diào)用add()函數(shù)給集合添加數(shù)據(jù);
3)使用coll2對(duì)象調(diào)用addAll()函數(shù),coll集合對(duì)象作為該函數(shù)的參數(shù),最后輸出coll2的結(jié)果;
代碼實(shí)現(xiàn)如下:
package cn.xuexi.demo1;
import java.util.ArrayList;
import java.util.Collection;
/*
* Collection接口中addAll方法的演示
*/
public class Collection AddAllDemo {
public static void main(String[] args) {
/*
*由于Collection是接口,所以不能創(chuàng)建Collection接口的對(duì)象,
*但是我們可以使用new關(guān)鍵字創(chuàng)建Collection接口下面的任意一個(gè)類(lèi)的對(duì)象,然后對(duì)象類(lèi)型變?yōu)镃ollection
*/
Collection coll=new ArrayList();//這里發(fā)生多態(tài)了
//再創(chuàng)建一個(gè)集合對(duì)象
Collection coll2 = new ArrayList();
//使用coll對(duì)象調(diào)用add函數(shù)向集合中引用類(lèi)型添加數(shù)據(jù)
coll.add("aaaa");
coll.add("bbbb");
coll.add("dddd");
coll.add("eeee");
//向集合coll2中添加數(shù)據(jù)
coll2.add("AAAA");
//將集合coll中的數(shù)據(jù)添加到集合coll2中
coll2.addAll(coll);
//輸出集合中的數(shù)據(jù)
System.out.println(coll2);
}
}
說(shuō)明:判斷集合中是否包含指定集合中的所有元素。
containsAll()方法是要求作為參數(shù)傳遞的集合中的元素需要全部在調(diào)用這個(gè)方法的集合中存在,才會(huì)返回true。
分析和步驟:
1)使用new關(guān)鍵字創(chuàng)建集合類(lèi)ArrayList的兩個(gè)對(duì)象coll和coll2,兩個(gè)對(duì)象的類(lèi)型是接口Collection;
2)使用coll和coll2對(duì)象分別調(diào)用add()函數(shù)給集合添加數(shù)據(jù);
3)使用coll對(duì)象調(diào)用containsAll()函數(shù),coll2集合對(duì)象作為該函數(shù)的參數(shù),最后輸出布爾類(lèi)型的返回結(jié)果;
package cn.xuexi.demo1;
import java.util.ArrayList;
import java.util.Collection;
/*
* Collection接口中containsAll方法的演示
*/
public class Collection ContainsAllDemo {
public static void main(String[] args) {
/*
*由于Collection是接口,所以不能創(chuàng)建Collection接口的對(duì)象,
*但是我們可以使用new關(guān)鍵字創(chuàng)建Collection接口下面的任意一個(gè)類(lèi)的對(duì)象,然后對(duì)象類(lèi)型變?yōu)镃ollection
*/
Collection coll=new ArrayList();//這里發(fā)生多態(tài)了
//再創(chuàng)建一個(gè)集合對(duì)象
Collection coll2=new ArrayList();
//使用coll對(duì)象調(diào)用add函數(shù)向集合中引用類(lèi)型添加數(shù)據(jù)
coll.add("aaaa");
coll.add("bbbb");
coll.add("dddd");
coll.add("eeee");
//向集合coll2中添加數(shù)據(jù)
coll2.add("AAAA");
//將集合coll中的數(shù)據(jù)添加到集合coll2中
coll2.addAll(coll);
//coll集合:"aaaa" "bbbb" "dddd""eeee"
//coll2 集合:"AAAA" "aaaa" "bbbb""dddd" "eeee"
//判斷集合coll中是否包含集合coll2中的所有集合,如果包含返回true,否則返回false
//boolean boo =coll.containsAll(coll2);//false 不包含
boolean boo =coll2.containsAll(coll);//true包含
//輸出返回值
System.out.println(boo);
}
}
說(shuō)明:
1)boolean removeAll(Collection c) :表示從調(diào)用這個(gè)函數(shù)執(zhí)行的集合中刪除當(dāng)前集合與指定集合中共同的元素,刪除交集;
2)boolean retainAll(Collection c) :表示從調(diào)用這個(gè)函數(shù)執(zhí)行的集合中刪除兩個(gè)集合中不同的元素,也可以理解為保留兩個(gè)集合中共有的元素,保留交集。
分析和步驟:
1)使用new關(guān)鍵字創(chuàng)建集合類(lèi)ArrayList的兩個(gè)對(duì)象coll和coll2,兩個(gè)對(duì)象的類(lèi)型是接口Collection;
2)使用coll和coll2對(duì)象分別調(diào)用add()函數(shù)給集合添加數(shù)據(jù);
3)使用coll對(duì)象分別調(diào)用removeAll()和retainAll()函數(shù),coll2集合對(duì)象作為該函數(shù)的參數(shù),最后輸出布爾類(lèi)型的返回結(jié)果和兩個(gè)集合對(duì)象coll和coll2;
public static void method_3() {
// 創(chuàng)建集合對(duì)象
Collection coll = new ArrayList();
Collection coll2 = new ArrayList();
coll.add("aaaa");
coll.add("bvvv");
coll.add("dddd");
coll2.add("aaaa");
coll2.add("dddd2");
/*
*coll.removeAll(coll2)
*是從coll集合中刪除 coll與coll2中相同的元素(交集)
*/
/*
boolean b = coll.removeAll(coll2);
System.out.println(coll);
System.out.println(coll2);
System.out.println(b);
*/
/*
*coll.retainAll(coll2)
*是從coll中刪除 coll與 coll2中不同的元素,也可以理解成保留2個(gè)集合的交集
*/
boolean b = coll.retainAll(coll2);
System.out.println(coll);
System.out.println(coll2);
System.out.println(b);
}
2.2.5、toArray()遍歷集合
遍歷就是指依次從容器中獲取每一個(gè)容器中的對(duì)象元素。
問(wèn)題1:我們之前直接通過(guò)輸出集合的對(duì)象名比如:System.out.println(coll);就可以輸出集合中的數(shù)據(jù)了,為什么還要遍歷集合呢?
我們之前通過(guò)輸出集合名的方式來(lái)輸出集合中的數(shù)據(jù)的方法是可以將集合中的數(shù)據(jù)輸出來(lái),但是那些輸出的都是將集合中的對(duì)象變成字符串然后拼接在一起輸出的,這樣輸出就改變了原來(lái)對(duì)象的意思了,我們希望當(dāng)時(shí)存儲(chǔ)到集合中是對(duì)象,取出來(lái)的時(shí)候仍然是對(duì)象,這樣不改變?cè)瓉?lái)對(duì)象元素的意思,可以使用對(duì)象操作對(duì)象本身的函數(shù)或者屬性。
問(wèn)題2:現(xiàn)在會(huì)使用集合中的專(zhuān)用遍歷方式嗎?
不會(huì)。只會(huì)對(duì)數(shù)組進(jìn)行遍歷
在Collection集合中存在一個(gè)方法,可以把集合對(duì)象轉(zhuǎn)為數(shù)組對(duì)象:
案例:對(duì)集合中的學(xué)生對(duì)象,進(jìn)行遍歷(集合轉(zhuǎn)數(shù)組的方式實(shí)現(xiàn))
分析和步驟:
1)定義一個(gè)Student類(lèi),在這個(gè)類(lèi)中定義兩個(gè)屬性name和age;
2)在這個(gè)類(lèi)中生成toString()函數(shù),對(duì)外提供get和set方法;
3)在定義一個(gè)類(lèi),在這個(gè)類(lèi)中創(chuàng)建集合對(duì)象stus;
4)使用集合對(duì)象stus調(diào)用add()函數(shù)向集合中添加學(xué)生對(duì)象;
5)使用集合對(duì)象stus調(diào)用toArray()函數(shù)將集合轉(zhuǎn)換為數(shù)組;
6)使用for循環(huán)遍歷數(shù)組,并根據(jù)數(shù)組名和下標(biāo)輸出對(duì)象即可;
package cn.xuexi.demo1;
import java.util.ArrayList;
import java.util.Collection;
import cn.xuexi.demo.Student;
/*
*遍歷集合
*/
public class Collection ToArrayDemo {
public static void main(String[] args) {
//創(chuàng)建集合對(duì)象
Collection coll=new ArrayList();
//創(chuàng)建學(xué)生對(duì)象
Student s=new Student("張三",18);
Student s1=new Student("李四",19);
Student s2=new Student("王五",20);
Student s3=new Student("鎖哥",21);
//將學(xué)生對(duì)象添加到集合中
coll.add(s);
coll.add(s1);
coll.add(s2);
coll.add(s3);
/*
*想要對(duì)集合進(jìn)行遍歷我們還沒(méi)有學(xué)習(xí),但是我們學(xué)習(xí)過(guò)怎樣對(duì)數(shù)組進(jìn)行遍歷
*所以我們可以將集合轉(zhuǎn)換為數(shù)組
*/
/*
int[] arr1={1,2,3};
int x=arr1[0];
String[] arr2={"ss","dd"};
Strings tr=arr2[0];
*/
Object[] arr = coll.toArray();
//遍歷數(shù)組
for (int i =0; i < arr.length; i++) {
//取出數(shù)組中的對(duì)象數(shù)據(jù)
Object obj=arr[i];
//轉(zhuǎn)換為Student類(lèi)型
Student stu=(Student)obj;
//打印Student類(lèi)中的屬性值
// System.out.println(stu.getName()+"======"+stu.getAge());
/*
*由于以上發(fā)生多態(tài),但是子類(lèi)Student類(lèi)中有非靜態(tài)成員函數(shù)toString(),所以根據(jù)多態(tài)的特 點(diǎn),
*對(duì)于非靜態(tài)函數(shù),如果子類(lèi)有優(yōu)先使用子類(lèi)中的函數(shù)
*/
System.out.println(obj.toString());
}
}
}
說(shuō)明:由于這里集合生成數(shù)組之后發(fā)生多態(tài)了,但是我們?cè)赟tudent類(lèi)中復(fù)寫(xiě)了Object類(lèi)中的toString()函數(shù),所以根據(jù)多態(tài)的特點(diǎn),對(duì)于非靜態(tài)函數(shù),如果子類(lèi)有優(yōu)先使用子類(lèi)中的函數(shù),直接輸出生成數(shù)組名即可。
注意:利用toArray()方法轉(zhuǎn)數(shù)組,并遍歷數(shù)組,雖然可以遍歷集合,但卻不是我們常用的方式。一般不建議使用。
3、迭代器(遍歷器)Iterator(掌握)
3.3.1、迭代器介紹
由于集合框架中的集合容器太多,而每個(gè)集合容器中保存的數(shù)據(jù)存儲(chǔ)的方式都不一樣。于是導(dǎo)致我們往出取數(shù)據(jù)的時(shí)候方式也完全不相同。
Java針對(duì)這些所有集合容器取出數(shù)據(jù)的方式進(jìn)行共性的抽取,于是針對(duì)所有的集合定義了一個(gè)接口,在這個(gè)接口中描述了所有集合容器的共性遍歷規(guī)則。
注意:對(duì)于集合取元素,無(wú)論是什么數(shù)據(jù)結(jié)構(gòu),最終共性的取出方式:
一個(gè)一個(gè)取,取之前先判斷,有,取一個(gè),沒(méi)有,結(jié)束。
這種取出的共性方式:迭代。迭代可以理解為取出或者遍歷。
而這個(gè)接口它就是Iterator,它中定義了集合最基本的遍歷方式:
Iterator接口的迭代(取出、遍歷)方式:
針對(duì)一個(gè)集合,需要遍歷的時(shí)候,應(yīng)該首先去判斷集合中有沒(méi)有元素(對(duì)象),有就取出這個(gè)元素,沒(méi)有就不用再進(jìn)行遍歷了。
hasNext()函數(shù)表示判斷容器中還有沒(méi)有元素,如果有返回true,我們就可以根據(jù)這個(gè)返回的結(jié)果確定到底還要不要遍歷這個(gè)集合容器
next()函數(shù)表示取出當(dāng)前遍歷到的那個(gè)元素。
void remove()表示刪除當(dāng)前迭代器對(duì)象指向的集合中的元素。
對(duì)于迭代器Iterator中的函數(shù)解釋和運(yùn)行原理如下圖所示:
說(shuō)明:可以把迭代器對(duì)象理解成為一個(gè)移動(dòng)的光標(biāo),開(kāi)始的時(shí)候,光標(biāo)會(huì)在集合容器的最上面,然后如果使用迭代器對(duì)象調(diào)用hasNext()函數(shù)的時(shí)候,光標(biāo)會(huì)指向集合中第一個(gè)元素,如果hasNext()函數(shù)返回true,則說(shuō)明有元素可以遍歷(迭代),則使用迭代器對(duì)象調(diào)用next()函數(shù)就會(huì)將當(dāng)前光標(biāo)所指向的元素取出來(lái),如果調(diào)用remove()函數(shù),就會(huì)刪除當(dāng)前光標(biāo)所指向的元素。
每執(zhí)行完一次next()函數(shù),光標(biāo)都會(huì)往下移動(dòng),直到移動(dòng)到集合的最低端,找不到元素為止。移動(dòng)到最底端代表著此迭代器對(duì)象也使用完畢。
如果還想再重新迭代該集合那么需要再根據(jù)此集合重新創(chuàng)建一個(gè)迭代器對(duì)象。
注意:在使用集合對(duì)象生成迭代器對(duì)象后,那么此時(shí)這個(gè)迭代器對(duì)象已經(jīng)記錄下來(lái)此時(shí)集合中的結(jié)構(gòu),在使用迭代器遍歷的時(shí)候,一定記住不能使用集合的對(duì)象來(lái)對(duì)集合中的元素進(jìn)行刪除或者添加,如果要改動(dòng)可以使用迭代器對(duì)象改動(dòng)集合,如果要改動(dòng)集合中的內(nèi)容可以根據(jù)改動(dòng)后的集合對(duì)象再重新生成迭代器對(duì)象。
3.3.2、迭代器的使用
分析:
注意:
在我們書(shū)寫(xiě)迭代器使用代碼的時(shí)候,我們首先應(yīng)該考略一個(gè)問(wèn)題,如何獲得迭代器對(duì)象?
其實(shí)通過(guò)以上的分析我們不難得知,要想獲得迭代器對(duì)象必須得先創(chuàng)建一個(gè)集合的對(duì)象,然后通過(guò)集合對(duì)象調(diào)用Collection接口中的iterator()函數(shù)就可以生成迭代器對(duì)象,如下圖所示:
說(shuō)明:由于集合種類(lèi)有很多,各不相同,所以迭代器對(duì)象也會(huì)有很多,針對(duì)不同集合獲得不同的迭代器對(duì)象,但是最后使用迭代器對(duì)象調(diào)用Iterator迭代器中的函數(shù)實(shí)現(xiàn)的效果是一致的,沒(méi)有區(qū)別,即:根據(jù)迭代器對(duì)象調(diào)用hasNext()函數(shù)查看集合容器中是否含有要遍歷的元素,調(diào)用next()函數(shù)獲取集合容器中的元素。
步驟:
1)使用new關(guān)鍵字創(chuàng)建集合類(lèi)ArrayList的對(duì)象coll,對(duì)象的類(lèi)型是接口Collection;
2)使用對(duì)象coll調(diào)用add()函數(shù)給集合添加數(shù)據(jù);
3)以前我們都是根據(jù)集合對(duì)象名coll將集合中的數(shù)據(jù)一次性輸出,而這里我們要先使用集合對(duì)象coll調(diào)用iterator()函數(shù)獲得迭代器對(duì)象;
4)然后根據(jù)迭代器對(duì)象調(diào)用next()函數(shù)依次取出數(shù)據(jù)并輸出;
5)如果多次調(diào)用next()函數(shù)有可能會(huì)發(fā)生異常,因?yàn)榧现械臄?shù)據(jù)已經(jīng)取完了,所以為了防止發(fā)生異常,我們?cè)谌?shù)據(jù)之前使用hasNext()函數(shù)進(jìn)行判斷一下,沒(méi)有數(shù)據(jù)就不用取數(shù)據(jù)了;
6)由于是多條語(yǔ)句,我們可以考略使用循環(huán)while或者for;
代碼如下:
運(yùn)行結(jié)果:
分析異常的原因:
說(shuō)明:當(dāng)?shù)鲗?duì)象指向集合時(shí),可以獲取集合中的元素,如果迭代器的光標(biāo)移動(dòng)集合的外邊時(shí),此時(shí)迭代器對(duì)象不再指向集合中的任何元素,會(huì)報(bào)NoSuchElementException沒(méi)有這個(gè)元素異常。
解決方案:在使用next()函數(shù)獲取集合中元素前,使用hasNext()判斷集合中是否還有元素。
上述代碼一條語(yǔ)句重復(fù)執(zhí)行多次,我們可以考慮使用循環(huán)來(lái)控制執(zhí)行的次數(shù),循環(huán)條件是 迭代器對(duì)象.hasNext()為false時(shí)表示集合中沒(méi)有元素可以獲取了,循環(huán)條件迭代器對(duì)象.hasNext() 為true的時(shí)候說(shuō)明還可以獲取元素。
package cn.xuexi.iterator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/*
*演示迭代器的使用
*/
public class IteratorDemo {
public static void main(String[] args) {
//創(chuàng)建集合對(duì)象
Collection coll=new ArrayList();
//向集合中添加數(shù)據(jù)
coll.add("aaaa");
coll.add("bbbb");
coll.add("cccc");
//根據(jù)當(dāng)前集合獲取迭代器對(duì)象
Iteratorit = coll.iterator();
//取出數(shù)據(jù)
/*System.out.println(it.next());//it.next()表示獲取迭代器對(duì)象指向集合中的數(shù)據(jù)
System.out.println(it.next());
System.out.println(it.next());
System.out.println(it.next());*/
//使用while循環(huán)遍歷集合
while(it.hasNext())//it.hasNext()表示循環(huán)條件,如果為true,說(shuō)明集合中還有元素可以獲取,否則沒(méi)有元素
{
//獲取元素并輸出
System.out.println(it.next());
}
/*
*注意:針對(duì)集合每次獲取到的迭代器對(duì)象,使用完之后,迭代器中的隱式光標(biāo)就已經(jīng)到了集合的最后,這樣就無(wú)法再去使用next獲取集合中的元素。如果還要獲取,需要重新在獲取一個(gè)迭代器對(duì)象。
*/
//報(bào)找不到元素異常,對(duì)于it迭代器對(duì)象,它已經(jīng)移動(dòng)到集合中最后了,再找就沒(méi)有元素了,只能重新獲得迭代器對(duì)象
//System.out.println(it.next());
//使用for循環(huán)遍歷集合 推薦開(kāi)發(fā)使用
/*for (Iterator it2 = coll.iterator(); it2.hasNext();) {
System.out.println(it2.next());
}*/
}
}
注意:針對(duì)集合每次獲取到的迭代器對(duì)象,使用完之后,迭代器中的隱式光標(biāo)就已經(jīng)到了集合的最后,這樣就
無(wú)法再去使用next獲取集合中的元素。如果還要獲取,需要重新在獲取一個(gè)迭代器對(duì)象。
while循環(huán)的迭代和for循環(huán)的迭代有什么不同?
while循環(huán)的迭代,由于初始化迭代器對(duì)象在while循環(huán)上面,在整個(gè)while循環(huán)結(jié)束后,迭代器對(duì)象還可以繼續(xù)使用,但是集合中已經(jīng)沒(méi)有數(shù)據(jù)了,如果還仍然使用迭代器對(duì)象繼續(xù)獲取數(shù)據(jù),會(huì)報(bào)異常,如果還要獲取,需要重新在獲取一個(gè)迭代器對(duì)象。所以對(duì)于while循環(huán)當(dāng)?shù)鲗?duì)象使用完之后,迭代器就會(huì)變成一個(gè)沒(méi)有用的垃圾,占內(nèi)存。
對(duì)于for循環(huán)的迭代,由于初始化迭代器對(duì)象在for循環(huán)小括號(hào)中,在整個(gè)for循環(huán)結(jié)束后,迭代器對(duì)象就不能繼續(xù)使用,也不會(huì)占內(nèi)存,所以建議大家以后在開(kāi)發(fā)中使用迭代器遍歷集合最好使用for循環(huán)。
總結(jié):在開(kāi)發(fā)中,建議大家使用迭代器遍歷集合的時(shí)候最好使用for循環(huán)。
3.3.3、迭代器注意細(xì)節(jié)
需求:遍歷集合,遇到"abc"就把它刪除。
分析和步驟:
1)使用new關(guān)鍵字創(chuàng)建集合類(lèi)ArrayList的對(duì)象coll,對(duì)象的類(lèi)型是接口Collection;
2)使用集合對(duì)象coll調(diào)用add()函數(shù)給集合中添加數(shù)據(jù);
3)使用for循環(huán)遍歷集合,取出每個(gè)元素,進(jìn)行判斷,只要當(dāng)前取出的這個(gè)元素是"abc",就把它從集合中刪除;
4)在for循環(huán)的初始化值位置上使用集合對(duì)象coll獲取迭代器對(duì)象;
5)使用迭代器中的next()函數(shù)獲取數(shù)據(jù)賦值給Object類(lèi)型;
6)使用判斷結(jié)構(gòu)對(duì)取出的數(shù)據(jù)和字符串”abc”進(jìn)行判斷,如果找到,則使用迭代器對(duì)象調(diào)用迭代器中的remove()函數(shù)進(jìn)行刪除,不要使用集合中的remove(obj)函數(shù),否則會(huì)報(bào)異常;
/*
*需求:遍歷集合,遇到"abc"就把它刪除。
*/
public class IteratorDemo2 {
public static void main(String[] args) {
Collection coll = new ArrayList();
coll.add("abc");
coll.add("bbbbb");
coll.add("dddd");
coll.add("xyz");
coll.add("ABC");
/*
*遍歷集合,取出每個(gè)元素,進(jìn)行判斷,只要當(dāng)前取出的這個(gè)元素是"abc"
*就把它從集合中刪除
*/
for( Iterator it = coll.iterator(); it.hasNext(); ){
//取出這個(gè)元素進(jìn)行判斷
Object obj = it.next();
if( obj.equals("abc") ){
/*
*當(dāng)我們使用迭代器對(duì)集合中的元素進(jìn)行迭代的時(shí)候,不允許使用集合自身的增刪函數(shù)
*對(duì)集合中的元素進(jìn)行操作。 如果真的需要?jiǎng)h除,這時(shí)只能使用迭代器自身的remove方法
*/
//coll.remove(obj);
it.remove();
}
}
System.out.println(coll);
}
}
說(shuō)明:如果使用集合中的remove(obj)函數(shù)進(jìn)行刪除,為什么會(huì)報(bào)異常?
由于迭代器對(duì)象是基于集合而來(lái)的,如果已經(jīng)獲取到了迭代器對(duì)象,就可以使用迭代器對(duì)象遍歷集合,而此時(shí)在遍歷集合的時(shí)候,如果使用集合對(duì)象調(diào)用集合中的函數(shù)對(duì)集合進(jìn)行增刪操作,那么對(duì)于迭代器對(duì)象而言就會(huì)導(dǎo)致最開(kāi)始生成迭代器對(duì)象和修改集合之后不一樣,而在java中是不允許這樣操作的,如果想要在迭代集合的時(shí)候刪除集合中的元素可以使用迭代器Iterator中的remove()函數(shù)。
總結(jié):
1、使用迭代器對(duì)集合進(jìn)行迭代的時(shí)候,不要使用集合自身的功能(函數(shù))對(duì)集合進(jìn)行增刪操作;
2、所有的迭代器當(dāng)?shù)Y(jié)束之后,那么這個(gè)迭代器對(duì)象(隱式光標(biāo))就位于集合的最后;
3、使用迭代器迭代集合的時(shí)候,每一個(gè)hasNext()方法都對(duì)應(yīng)一個(gè)next()函數(shù),不要一個(gè)hasNext()方法對(duì)應(yīng)多個(gè)next()函數(shù)。
如下圖所示,就是一個(gè)hasNext()函數(shù)對(duì)應(yīng)多個(gè)next()函數(shù),使用是錯(cuò)誤的。
4.可以使用增強(qiáng)for循環(huán)遍歷集合更加簡(jiǎn)單一些;
但是使用增強(qiáng)for循環(huán)的時(shí)候需要注意集合中的數(shù)據(jù)類(lèi)型是Object,因?yàn)榧现锌梢源鎯?chǔ)各種引用類(lèi)型數(shù)據(jù),而Object類(lèi)是所有引用類(lèi)型數(shù)據(jù)的父類(lèi)。
代碼演示如下:
4、集合的細(xì)節(jié)
集合的細(xì)節(jié):
1)集合中正常情況下是不能存儲(chǔ)基本類(lèi)型數(shù)據(jù),但是在JDK1.5后可以直接在add方法中書(shū)寫(xiě)基本類(lèi)型數(shù)據(jù),因?yàn)榈讓釉诓僮鲿r(shí)會(huì)對(duì)基本類(lèi)型數(shù)據(jù)進(jìn)行裝箱。
2)集合中存儲(chǔ)的任何類(lèi)型的元素,在存儲(chǔ)到集合中時(shí),全部都會(huì)轉(zhuǎn)為Object類(lèi)型;
3)從集合中取出元素時(shí),取出的元素類(lèi)型全部都是Object類(lèi)型,如果想要使用類(lèi)中特有的成員時(shí),需要向下轉(zhuǎn)型;
例如上述存儲(chǔ)在集合中的自定義Student類(lèi),想要使用Student類(lèi)中的特有的get和set函數(shù):
package cn.xuexi.iterator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import cn.xuexi.demo.Student;
public class IteratorDemo1 {
public static void main(String[] args) {
//創(chuàng)建集合類(lèi)對(duì)象
Collection coll=new ArrayList();
//向集合中添加數(shù)據(jù)
coll.add(new Student("張三",19));
coll.add("aaaa");
//遍歷取出集合中的數(shù)據(jù)
for(Iteratorit = coll.iterator(); it.hasNext();) {
Object obj = it.next();
/*
*想通過(guò)取出的對(duì)象調(diào)用Student類(lèi)中特有的getName()和getAge()函數(shù)獲得屬性值
*由于getName()和getAge()函數(shù)是Student類(lèi)中的特有的函數(shù),而從集合中取出的數(shù)據(jù)
*都是Object類(lèi)型,要想使用子類(lèi)Student特有的函數(shù),必須向下轉(zhuǎn)型,向下轉(zhuǎn)型有風(fēng)險(xiǎn)
*使用需謹(jǐn)慎,使用instanceof判斷轉(zhuǎn)型的數(shù)據(jù)類(lèi)型
*/
if(obj instanceof Student)
{
//說(shuō)明是Student類(lèi)型
Student stu=(Student)obj;
System.out.println(stu.getName()+"====="+stu.getAge());
}
}
}
}
4)集合容器是用來(lái)保存對(duì)象的。而真正給集合中保存的不是當(dāng)前那個(gè)對(duì)象,而是對(duì)象在堆內(nèi)存中的內(nèi)存地址。
給集合中保存自定義對(duì)象:
a.使用上述自定義的Student類(lèi),在類(lèi)中定義name和age屬性,生成get和set方法;
b.隨便定義一個(gè)測(cè)試類(lèi),在main函數(shù)中創(chuàng)建集合對(duì)象,同時(shí)創(chuàng)建Student類(lèi)的對(duì)象;
c.將Student類(lèi)的對(duì)象添加到集合中,并迭代集合,遍歷輸出結(jié)果,會(huì)發(fā)現(xiàn)打印的是Student類(lèi)的對(duì)象的地址值
d.如果在Student類(lèi)中復(fù)寫(xiě)toString()函數(shù)就會(huì)打印name和age的屬性值;
代碼如下:
自定義學(xué)生類(lèi):
package cn.xuexi.demo;
//描述學(xué)生
public class Student {
//屬性
String name;
int age;
//定義構(gòu)造函數(shù)給屬性初始化值
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//給屬性生成get和set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age)
{
this.age = age;
}
//生成toString()函數(shù)
public StringtoString() {
return "Student [name=" + name +", age=" + age + "]";
}*/
}
測(cè)試類(lèi):
package cn.xuexi.iterator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import cn.xuexi.demo.Student;
public class IteratorDemo2 {
public static void main(String[] args) {
//創(chuàng)建集合類(lèi)對(duì)象
Collection coll=new ArrayList();
//向集合中添加數(shù)據(jù)
coll.add(new Student("張三",19));
//遍歷取出集合中的數(shù)據(jù)
for(Iteratorit = coll.iterator(); it.hasNext();) {
/*
*如果自定義Student類(lèi)中不復(fù)寫(xiě)toString()函數(shù)那么就會(huì)輸出一串內(nèi)存地址
* cn.xuexi.demo.Student@6d9dd520
*/
System.out.println(it.next());
}
}
}
內(nèi)存圖解如下圖所示:
5、集合使用的步驟
步驟總結(jié):
1、創(chuàng)建集合
2、添加元素
3、遍歷集合:
1)獲取迭代器對(duì)象;
2)循環(huán)迭代集合;