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 }    
受限泛型的使用示例

 

 

 

 

 

 

 

 

 

 

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

相关文章
相关标签/搜索