Iterator迭代器和泛型

iterator迭代器

迭代器的定義和使用

在程序開發中,常常須要遍歷集合中的全部元素。針對這種需求,JDK專門提供了一個接口java.util.IteratorIterator接口也是Java集合中的一員,但它與CollectionMap接口有所不一樣,Collection接口與Map接口主要用於存儲元素,Iterator主要用於迭代訪問(即遍歷)Collection中的元素,所以Iterator對象也被稱爲迭代器。java

想要遍歷Collection集合,那麼就要獲取該集合迭代器完成迭代操做,下面介紹一下獲取迭代器的方法【Collection接口中有一個方法】:數組

1 public Iterator iterator(): 獲取集合對應的迭代器,用來遍歷集合中的元素的。

 迭代:即Collection集合元素的通用獲取方式。在取元素以前先要判斷集合中有沒有元素,若是有,就把這個元素取出來,繼續在判斷,若是還有就再取出出來。一直把集合中的全部元素所有取出。這種取出方式專業術語稱爲迭代。ide

Iterator中經常使用方法:學習

  public E next():返回迭代的下一個元素。優化

  public boolean hasNext():若是仍有元素能夠迭代,則返回 true。this

使用步驟:
  1.使用集合中的方法iterator()獲取迭代器的實現類對象,使用Iterator接口接收(多態)spa

    Iterator<E>接口也是有泛型的,迭代器的泛型跟着集合走,集合是什麼泛型,迭代器就是什麼泛型設計

  2.使用Iterator接口中的方法hasNext判斷還有沒有下一個元素code

  3.使用Iterator接口中的方法next取出集合中的下一個元素對象

 1 import java.util.ArrayList;
 2 import java.util.Collection;
 3 import java.util.Iterator;
 4 
 5 public class Demo01Iterator {
 6     public static void main(String[] args) {
 7         //建立一個集合對象
 8         Collection<String> coll = new ArrayList<>();
 9         //往集合中添加元素
10         coll.add("姚明");
11         coll.add("科比");
12         coll.add("麥迪");
13         coll.add("詹姆斯");
14         coll.add("艾弗森");
15 
16         /*
17             1.使用集合中的方法iterator()獲取迭代器的實現類對象,使用Iterator接口接收(多態)
18             注意:
19                 Iterator<E>接口也是有泛型的,迭代器的泛型跟着集合走,集合是什麼泛型,迭代器就是什麼泛型
20          */
21         //多態  接口            實現類對象
22         Iterator<String> it = coll.iterator();
23 
24 
25         /*
26             發現使用迭代器取出集合中元素的代碼,是一個重複的過程
27             因此咱們可使用循環優化
28             不知道集合中有多少元素,使用while循環
29             循環結束的條件,hasNext方法返回false
30          */
31         while(it.hasNext()){
32             String e = it.next();
33             System.out.println(e);
34         }
35 
36 
37 
38         // 下面的代碼是一個一個在判斷取。
39         // 若是判斷爲false任然使用next方法取拋出NoSuchElementException異常
40         
41        /* //2.使用Iterator接口中的方法hasNext判斷還有沒有下一個元素
42         boolean b = it.hasNext();
43         System.out.println(b);//true
44         //3.使用Iterator接口中的方法next取出集合中的下一個元素
45         String s = it.next();
46         System.out.println(s);//姚明
47 
48         b = it.hasNext();
49         System.out.println(b);
50         s = it.next();
51         System.out.println(s);
52 
53         b = it.hasNext();
54         System.out.println(b);
55         s = it.next();
56         System.out.println(s);
57 
58         b = it.hasNext();
59         System.out.println(b);
60         s = it.next();
61         System.out.println(s);
62 
63         b = it.hasNext();
64         System.out.println(b);
65         s = it.next();
66         System.out.println(s);
67 
68         b = it.hasNext();
69         System.out.println(b);//沒有元素,返回false
70         s = it.next();//沒有元素,在取出元素會拋出NoSuchElementException沒有元素異常
71         System.out.println(s);*/
72     }
73 }
74         
使用步驟示例

迭代器原理

在調用Iterator的next方法以前,迭代器的索引位於第一個元素以前,不指向任何元素,當第一次調用迭代器的next方法後,迭代器的索引會向後移動一位,指向第一個元素並將該元素返回,當再次調用next方法時,迭代器的索引會指向第二個元素並將該元素返回,依此類推,直到hasNext方法返回false,表示到達了集合的末尾,終止對元素的遍歷。

原理圖:

加強for

加強for循環(也稱for each循環)是JDK1.5之後出來的一個高級for循環,專門用來遍歷數組和集合的。

它的內部原理實際上是個Iterator迭代器,因此在遍歷的過程當中,不能對集合中的元素進行增刪操做。

Collection<E>extends Iterable<E>:全部的單列集合均可以使用加強for

public interface Iterable<T>:實現這個接口容許對象成爲 "foreach" 語句的目標。

語法:

1 for(元素的數據類型  變量 : Collection集合or數組){ 
2       //寫操做代碼
3 }
 1 import java.util.ArrayList;
 2 
 3 public class Demo02Foreach {
 4     public static void main(String[] args) {
 5         demo02();
 6     }
 7 
 8     //使用加強for循環遍歷集合
 9     private static void demo02() {
10         ArrayList<String> list = new ArrayList<>();
11         list.add("aaa");
12         list.add("bbb");
13         list.add("ccc");
14         list.add("ddd");
15         for(String s : list){
16             System.out.println(s);
17         }
18     }
19 
20     //使用加強for循環遍歷數組
21     private static void demo01() {
22         int[] arr = {1,2,3,4,5};
23         for(int i:arr){
24             System.out.println(i);
25         }
26     }
27 }
使用加強for代碼示例

泛型

爲何引入泛型

在前面學習集合時,咱們都知道集合中是能夠存聽任意對象的,只要把對象存儲集合後,那麼這時他們都會被提高成Object類型。當咱們在取出每個對象,而且進行相應的操做,這時必須採用類型轉換。

 1 public class GenericDemo {
 2     public static void main(String[] args) {
 3         Collection coll = new ArrayList();
 4         coll.add("abc");
 5         coll.add("itcast");
 6         coll.add(5);//因爲集合沒有作任何限定,任何類型均可以給其中存放
 7         Iterator it = coll.iterator();
 8         while(it.hasNext()){
 9             //須要打印每一個字符串的長度,就要把迭代出來的對象轉成String類型
10             String str = (String) it.next();
11             System.out.println(str.length());
12         }
13     }
14 }
View Code

上面的程序在運行時發生了問題java.lang.ClassCastException。 爲何會發生類型轉換異常呢?

咱們來分析下:因爲集合中能夠存儲任意類型的元素。致使取出時強轉引起運行時 ClassCastException。 怎麼來解決這個問題呢?

Collection雖然能夠存儲各類對象,但實際上一般Collection只存儲同一類型對象。例如都是存儲字符串對象。

所以在JDK5以後,新增了泛型(Generic)語法,讓你在設計API時能夠指定類或方法支持泛型,這樣咱們使用API的時候也變得更爲簡潔,並獲得了編譯時期的語法檢查。

泛型定義:能夠在類或方法中預支地使用未知的類型。

使用泛型的好處與弊端

好處:

  1.避免了類型轉換的麻煩,存儲的是什麼類型,取出的就是什麼類型

  2.把運行期異常(代碼運行以後會拋出的異常),提高到了編譯期(寫代碼的時候會報錯)

弊端:

  泛型是什麼類型,只能存儲什麼類型的數據。

泛型的定義和使用

定義和使用含有泛型的類

含有泛型的類的定義

1 修飾符 class 類名<表明泛型的變量> {  }

注意:泛型是數據類型的一部分,咱們將類名與泛型合併一塊兒看作數據類型。

泛型是一個未知的數據類型,當咱們不肯定使用什麼數據類型的時候,可使用泛型。泛型能夠接收任意的數據類型,可使用Integer,String,Student...

含有泛型的類的使用

建立對象的時候肯定泛型的數據類型。

語法:

1 ArrayList<String> list = new ArrayList<String>();

這時在類定義時候的表明泛型的變量將會被String所代替。

 1 public class GenericClass<E> {
 2     private E name;
 3 
 4     public E getName() {
 5         return name;
 6     }
 7 
 8     public void setName(E name) {
 9         this.name = name;
10     }
11 }
12 
13 
14 ----------------------------------------------
15 public class Demo02GenericClass {
16     public static void main(String[] args) {
17 
18         //不寫泛型默認爲Object類型
19         GenericClass gc = new GenericClass();
20         gc.setName("只能是字符串");
21         Object obj = gc.getName();// 只能是字符串
22 
23 
24         //建立GenericClass對象,泛型使用Integer類型
25         GenericClass<Integer> gc2 = new GenericClass<>();
26         gc2.setName(1);
27         Integer name = gc2.getName();
28         System.out.println(name);// 1
29 
30 
31         //建立GenericClass對象,泛型使用String類型
32         GenericClass<String> gc3 = new GenericClass<>();
33         gc3.setName("小明");
34         String name1 = gc3.getName();
35         System.out.println(name1);// 小明
36     }
37 }
自定義含有泛型的類並使用

定義和使用含有泛型的方法

含有泛型的方法的定義

語法:

定義含有泛型的方法:泛型定義在方法的修飾符返回值類型之間

1 修飾符 <泛型> 返回值類型(能夠爲任意類型,也能夠爲泛型) 方法名(參數列表(使用泛型)){
2             方法體;
3 }

含有泛型的方法,在調用方法的時候肯定泛型數據類型。傳遞什麼類型的參數,泛型就是什麼類型

含有泛型的方法的使用

和普通方法使用同樣。當有返回值爲泛型的使用。那麼傳遞的是什麼類型的參數,就要用什麼什麼類型接收。

 1 public class GenericMethod {
 2     //定義一個含有泛型的方法。而且返回的也是泛型
 3     public <M> M method01(M m){
 4         System.out.println(m);
 5         return m;
 6     }
 7 
 8 
 9     // 定義一個含有泛型的方法。
10     public <M> void method02 (M m){
11         System.out.println(m);
12         return m;
13     }
14 
15 
16     //定義一個含有泛型的靜態方法
17     public static <S> void method03 (S s){
18         System.out.println(s);
19     }
20 }
21 
22 
23 ------------------------------------------------------------------
24 public class Demo03GenericMethod {
25     public static void main(String[] args) {
26         //建立GenericMethod對象
27         GenericMethod gm = new GenericMethod();
28 
29         /*
30             調用含有泛型的方法method01
31             傳遞什麼類型,泛型就是什麼類型
32          */
33         int a = gm.method01(10);
34         System.out.println("a:"+a);
35 
36         String b = gm.method01("abc");
37         System.out.println("b:"+b);
38 
39 
40         System.out.println("==============");
41         gm.method02(8.8);
42         gm.method02(true);
43 
44 
45         System.out.println("==============");
46         gm.method02("靜態方法,不建議建立對象使用");
47 
48         //靜態方法,經過類名.方法名(參數)能夠直接使用
49         GenericMethod.method03("靜態方法");
50         GenericMethod.method03(1);
51     }
52 }
含有泛型的方法的定義和使用

定義和使用含有泛型的接口

含有泛型的接口的定義

1 修飾符 interface接口名<表明泛型的變量> {
2     // 方法
3 }

含有泛型的接口的使用

第一種使用方式:定義接口的實現類,實現接口,指定接口的泛型。

源碼中的使用:Scanner類實現了Iterator接口,並指定接口的泛型爲String,因此重寫的next方法泛型默認就是String

1 public final class Scanner implements Iterator<String>{
2     public String next() {}
3 }
 1 public interface GenericInterface<I> {
 2     public abstract void method(I i);
 3 
 4     public abstract I get();
 5 }
 6 
 7 
 8 ---------------------------------------------------
 9 public class GenericInterfaceImpl1 implements GenericInterface<String>{
10     @Override
11     public void method(String s) {
12         System.out.println(s);
13     }
14 
15     @Override
16     public String get() {
17         return null;
18     }
19 }
20 
21 
22 ------------------------------------------------------------------------------
23 public class Demo04GenericInterface {
24     public static void main(String[] args) {
25         //建立GenericInterfaceImpl1對象
26         GenericInterfaceImpl1 gi1 = new GenericInterfaceImpl1();
27         // 只能傳遞字符串
28         gi1.method("字符串");
29 
30     }
31 }
第一種方式代碼示例

第二種使用方式:接口使用什麼泛型,實現類就使用什麼泛型,類跟着接口走。就至關於定義了一個含有泛型的類,建立對象的時候肯定泛型的類型。

 1     public interface List<E>{
 2         boolean add(E e);
 3         E get(int index);
 4     }
 5 
 6 
 7     public class ArrayList<E> implements List<E>{
 8         public boolean add(E e) {}
 9         public E get(int index) {}
10     }
 1 public interface GenericInterface<I> {
 2     public abstract void method(I i);
 3 
 4     public abstract I get();
 5 }
 6 
 7 
 8 ------------------------------------------------------
 9 public class GenericInterfaceImpl2<I> implements GenericInterface<I> {
10     @Override
11     public void method(I i) {
12         System.out.println(i);
13     }
14 
15     @Override
16     public I get() {
17         return null;
18     }
19 }
20 
21 
22 ---------------------------------------------------------------------------
23 public class Demo04GenericInterface {
24     public static void main(String[] args) {
25 
26         //建立GenericInterfaceImpl2對象
27         GenericInterfaceImpl2<Integer> gi2 = new GenericInterfaceImpl2<>();
28         // 建立的對象爲何類型就能夠傳遞什麼類型
29         gi2.method(10);
30 
31         GenericInterfaceImpl2<Double> gi3 = new GenericInterfaceImpl2<>();
32         gi3.method(8.8);
33     }
34 }
第二種含有泛型的接口使用方式

泛型通配符

通配符的基本使用 

?:表明任意的數據類型

使用方式:

  不能建立對象使用

  只能做爲方法的參數使用

 1 import java.util.ArrayList;
 2 import java.util.Iterator;
 3 
 4 public class Demo05Generic {
 5     public static void main(String[] args) {
 6         ArrayList<Integer> list01 = new ArrayList<>();
 7         list01.add(1);
 8         list01.add(2);
 9 
10         ArrayList<String> list02 = new ArrayList<>();
11         list02.add("a");
12         list02.add("b");
13 
14         printArray(list01);
15         printArray(list02);
16 
17         // 不能建立對象使用
18         //ArrayList<?> list03 = new ArrayList<?>();
19     }
20 
21     /*
22         定義一個方法,能遍歷全部類型的ArrayList集合
23         這時候咱們不知道ArrayList集合使用什麼數據類型,能夠泛型的通配符?來接收數據類型
24         注意:
25             泛型沒有繼承概念的
26      */
27     public static void printArray(ArrayList<?> list){
28         //使用迭代器遍歷集合
29         Iterator<?> it = list.iterator();
30 
31         while(it.hasNext()){
32             //it.next()方法,取出的元素是Object,能夠接收任意的數據類型
33             Object o = it.next();
34             System.out.println(o);
35         }
36 
37     }
38 }
通配符的基本使用

通配符的高級使用——受限泛型

泛型的上限限定: ? extends E  表明使用的泛型只能是E類型的子類/自己

泛型的下限限定: ? super E    表明使用的泛型只能是E類型的父類/自己

 1 import java.util.ArrayList;
 2 import java.util.Collection;
 3 
 4 /*
 5     泛型的上限限定: ? extends E  表明使用的泛型只能是E類型的子類/自己
 6     泛型的下限限定: ? super E    表明使用的泛型只能是E類型的父類/自己
 7  */
 8 public class Demo06Generic {
 9     public static void main(String[] args) {
10          
11         /*
12             類與類之間的繼承關係
13             Integer extends Number extends Object
14             String extends Object
15          */
16         Collection<Integer> list1 = new ArrayList<Integer>();
17         Collection<String> list2 = new ArrayList<String>();
18         Collection<Number> list3 = new ArrayList<Number>();
19         Collection<Object> list4 = new ArrayList<Object>();
20 
21         getElement1(list1);
22         //getElement1(list2);//報錯
23         getElement1(list3);
24         //getElement1(list4);//報錯
25 
26         //getElement2(list1);//報錯
27         //getElement2(list2);//報錯
28         getElement2(list3);
29         getElement2(list4);
30     }
31 
32     // 泛型的上限:此時的泛型?,必須是Number類型或者Number類型的子類
33     public static void getElement1(Collection<? extends Number> coll){}
34     // 泛型的下限:此時的泛型?,必須是Number類型或者Number類型的父類
35     public static void getElement2(Collection<? super Number> coll){}
36 
37 }    
受限泛型的使用示例

 

 

 

 

 

 

 

 

 

 

--------------------

相關文章
相關標籤/搜索