Collection集合、Iterator迭代器、泛型

1、Collection集合

1.1、集合概述

集合:集合是Java中提供的一种容器技术,可以用来存储多个数据。

集合和数组都是容器技术,它们区别是:
●数组的长度是固定的,集合的长度是可变的
●数组中存储的是同一类型的元素,可以存储基本数据类型值,集合存储的都是对象,而且对象的类型可以不一致,在开发中一般当对象多的时候,使用集合进行存储。

1.2、集合框架

Java提供了满足各种需求的API,在使用这些API前,首先了解其继承与接口的操作架构,才能了解何时用哪个类,以及类之间如何彼此合作,从而达到灵活运用。

集合按照其存储结构可以分为两大类,分别是:单列集合java.util.Collection和双列集合java.util.Map,本章主要学习Collection集合。
在这里插入图片描述
Collection:单列集合类的根接口,用于存储一系列符合某种规则的元素,它由两个重要的子接口,分别是:java.util.List和java.util.Set。其中,List的特点是:元素有序(会按照添加的顺序进行元素的输出),而且可以重复(重复指的是内容一致);Set的特点是:元素无序(输出时无序),而且元素不可以重复。

List接口的主要实现类:

  1. java.util.ArrayList
  2. java.util.LinkedList
  3. java.util.Vector

Set接口的主要实现类:

  1. java.util.HashSet
  2. java.util.LinkedHashSet
  3. java.util.TreeSet

集合本身是一个工具类,它存放在java.util包中。

1.3、Collection常用功能

Collection是所有单列集合的父接口,因此在Collection中定义了单列集合通用的一些方法,这些方法可用于操作所有的单列集合。方法如下:
●public boolean add(E e):把给定的对象添加到当前集合中
● public boolean addAll(Collection<? extends E> c):将指定集合中的所有元素添加到此集合
● public void clear():从此集合中删除所有元素(可选操作)。.
● public boolean contains(Object o) :如果此集合包含指定的元素,则返回 true 。
● public boolean isEmpty():判断当前集合是否为空
● public boolean remove(Object o):从该集合中删除指定元素的单个实例(如果存在)(可选操作)。
● public int size():返回集合中元素的个数
● public Object[] toArray():把集合中的元素,存储到数组中

package com.bdit;

import java.util.ArrayList;
import java.util.Collection;

/*
Collection集合方法的应用
 */
public class Test1 {
    
    
    public static void main(String[] args) {
    
    
        Collection c1=new ArrayList();
        //添加元素到集合中
        c1.add("zhangsan");
        c1.add(100);//
        c1.add(96.69);
        c1.add(false);
        System.out.println("是否为空:"+c1.isEmpty());
        System.out.println("是否包含:"+c1.contains(1000));
        System.out.println("移除元素:"+c1.remove(100));
        System.out.println("元素的个数:"+c1.size());
        Collection c2=new ArrayList();
        c2.addAll(c1);
        System.out.println(c2);
    }
}

2、Iterator迭代器

2.1、Iterator接口

在程序开发中,经常需要遍历集合的所有元素,针对这种情况,JDK专门提供了一个接口java.util.Iterator。Iterator接口也是java集合中的一员,但它与Collection、Map接口有所不同。Collectionu接口与Map接口主要用于存储元素。而Iterator主要用于迭代访问(即遍历)Collection中的元素,因此Iterator对象也被称为迭代器。

想要遍历Collection集合,那么就要获取该集合迭代器完成迭代操作。
●public Iterator iterator():获取集合对应的迭代器,用来遍历集合中的元素

迭代的概念:
●迭代,即Collection集合元素的通用获取方式,在去元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续再判断,如果还有就继续取出来,一直把集合中所有的元素全部取出。这种取出方式专业术语称为迭代。
●Iterator常用方法:

  1. public E next():返回迭代的下一个元素
  2. public E next():返回迭代的下一个元素
package com.bdit;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/*
Itertor迭代器
 */
public class Test2 {
    
    
    public static void main(String[] args) {
    
    
        Collection c1=new ArrayList();
        c1.add("刘备");
        c1.add("关羽");
        c1.add("张飞");
        c1.add("赵子龙");
        c1.add("黄盖");

        System.out.println(c1);

        //获取集合的迭代器对象
        Iterator it=c1.iterator();
        while(it.hasNext()){
    
    
            System.out.println(it.next());
        }

        //此处会发生java.util.NoSuchElementException
        //如果迭代完毕后,继续调用next方法,将会发生以上异常
        System.out.println(it.next());
    }
}

2.2、迭代器的实现原理

当遍历集合时,首先通过调用集合的iterator()方法获取迭代器对象,然后使用hashNext()方法判断集合中是否存在下一个元素。如果存在,则调用next()方法将元素取出,否则说明已经到达了集合末尾,停止遍历元素。
Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素,为了更好的理解迭代器的工作原理,可以参考一下下列图片:
在这里插入图片描述
在调用iterator的next()方法之前,迭代器的索引位于第一个元素之前,不指向任何元素。当第一次调用迭代器的next方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回,当再次调用next()方法时,迭代器的索引会指向第二个元素并将该元素返回,以此类推,直到hasNext()方法返回false,表示到达了集合的末尾,终止对元素的遍历。

2.3、增强for循环

增强for循环(也称for each循环)是JDK1.5以后新增的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历过程中,不能对集合中元素进行其它操作。
【使用增强的for循环,无法直接获取每个元素的下标值】
【增强的for循环,只适合用来对数组或集合中的元素进行遍历操作】

package com.bdit;

import java.util.ArrayList;
import java.util.Collection;

public class Test3 {
    
    
    public static void main(String[] args) {
    
    
        Collection c1=new ArrayList();
        c1.add("刘备");
        c1.add("关羽");
        c1.add("张飞");
        c1.add("赵子龙");
        c1.add("黄盖");

		//增强for循环
        for(Object str:c1){
    
    
            System.out.println(str.toString());
        }
    }
}

3、泛型

3.1、泛型概念

集合中可以存放任意对象的,只要把对象存储到集合后,那么这时对象都会被提升(向上转型)为Object类型。当我们在取出每一个对象,并且进行相应操作,这时必须采用类型转换(向下转型)。
观察下面代码:

package com.bdit;

import java.util.ArrayList;
import java.util.Collection;

/*
往集合中添加自定义类对象
 */
public class Test4 {
    
    
    public static void main(String[] args) {
    
    
        Collection c1=new ArrayList();
        c1.add(new Student(1001,"张三",22));
        c1.add(new Student(1002,"李四",23));
        c1.add(new Student(1003,"王五",24));
        c1.add(new Student(1004,"赵六",25));
		//for(Object obj:c1){
    
    
		//Test4 student=(Test4)obj;
		//System.out.println(student);
		//}
        for(Object obj:c1){
    
    
            Student student=(Student)obj;
            System.out.println(student);
        }

    }
}

程序在运行时发生了问题java.lang.ClassCastException。为什么会发生类型转换异常呢?分析:
由于集合中什么类型的元素都可以存储,导致取出时强转引发运行时ClassCastException。怎么来解决这个问题呢?Collection虽然可以存储各种对象,但实际上通常Collection只存储一种类型即Object类型。因此在JDK5之后,新增了泛型(Generic)语法,让你在设计API时可以指定类或方法支持泛型,这样我们使用API的时候就变得更为简洁,并通过了编译时期的语法检查。

泛型:可以在类或方法中预支地使用未知的类型。

一般在创建对象时,将未知类型确定为具体类型,当没有指定泛型时,默认类型为Object类型。

3.2、使用泛型的好处

泛型有哪些好处:

  1. 将运行时期的ClassCastException,转移到编译时期,编译失败
  2. 避免了类型强转的麻烦

3.3、泛型的定义与使用

消除类型转换

集合类<泛型类型> 对象名=new 集合类<>();

package com.bdit;

import java.util.ArrayList;
import java.util.Collection;

/*
泛型
 */
public class Test5 {
    
    
    public static void main(String[] args) {
    
    
        Collection<Student> c1=new ArrayList<>();
        c1.add(new Student(1001,"张三",22));
        c1.add(new Student(1002,"李四",23));
        c1.add(new Student(1003,"王五",24));
        c1.add(new Student(1004,"赵六",25));

        for (Student stu:c1){
    
    
            System.out.println(stu);
        }
    }
}

定义和使用含有泛型的类

定义格式:

修饰符 class 类名<代表泛型的变量>{
    
    

}

自定义泛型类:

package com.bdit;
/*
自定义泛型类
 */
public class Test6 {
    
    
    public static void main(String[] args) {
    
    
        MyClass<String> myClass=new MyClass<>();
        myClass.setName("张三");
        System.out.println(myClass.getName());
    }
}

class MyClass<MVP>{
    
    
    private MVP name;

    public void setName(MVP name){
    
    
        this.name=name;
    }

    public MVP getName(){
    
    
        return name;
    }
}

在创建泛型类的对象时,必须给泛型类型确定为具体类型
例如:MyClass myClass=new MyClass<>();
在此类中MVP就相当于是泛型变量,那么创建对象时传递过来的具体类型,会把泛型类中所有使用到泛型变量的地方,替换为具体类型。

含有泛型的方法

定义格式:

修饰符 <代表泛型的变量> 返回值类型 方法名(参数列表){
    
    

}
package com.bdit;
/*
泛型方法
 */
public class Test7 {
    
    
    public static void main(String[] args) {
    
    
        Test7 test7=new Test7();
        test7.show("张三");

        System.out.println(test7.show2(100));
    }
    public <M> void show(M m){
    
    
        System.out.println(m.getClass());
    }

    public <M> M show2(M m){
    
    
        System.out.println(m.getClass());
        return m;
    }
}

【无论使用泛型类、泛型方法、泛型接口,传递的泛型类型只能是引用类型】

含有泛型的接口

定义格式:

修饰符 interface 接口名<代表泛型的变量>{
    
    
}
package com.bdit;
/*
泛型接口
 */
public class Test8 {
    
    
    public static void main(String[] args) {
    
    
        MyImpl1<String> myImpl1=new MyImpl1<>();
        myImpl1.add("张三");
    }
}

interface MyInter<E>{
    
    
    public void add(E e);

    public E get();
}

//定义实现类
class MyImpl1<E> implements MyInter<E>{
    
    


    @Override
    public void add(E e) {
    
    

    }

    @Override
    public E get() {
    
    
        return null;
    }
}

【不能直接new泛型变量的对象,因为无法保证泛型变量就一定是类】

猜你喜欢

转载自blog.csdn.net/vlucky_long/article/details/108555914