【集合、迭代、泛型】

【集合、迭代、泛型】

Collection集合

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

集合和数组都是容器,两者之间的区别:

  • 数组的长度是固定的,集合的长度是可变的。
  • 数组中存储的是同一类型的元素,可以存储基本数据类型值。集合存储的都是对象,而且对象的类型可以不一致,在开发中一般当对象多的时候,使用集合进行存储。

集合框架API

学习集合的目标:

  • 1、会使用集合存储数据;
  • 2、会遍历集合,把数据取出来;
  • 3、掌握每种集合的特性。

集合框架的学习方式:

  • 1.学习顶层:学习顶层接口(或者抽象类)中共性的方法,所有的子类都可以使用。
  • 2.使用底层:顶层不是接口就是抽象类,无法对象使用,需要创建底层的子类对象使用。
extends
implements
implements
implements
extends
implements
implements
implements
Collection接口
List接口
Vector集合
ArrayList集合
LinkedList集合
Set接口
TreeSet集合
HashSet集合
LinkedHashSet集合

Collection接口:

  • 1.定义的是所有单列集合中共性的方法
  • 2.所有的单列集合都可以使用共性的方法
  • 3.没有带索引的方法

List接口

  • 1.有序的集合(存储和取出元素顺序相同)
  • 2.允许存储重复的元素
  • 3.有索引,可以使用普通的for循环遍历

Set接口:

  • 2.不允许存储重复元素
  • 3.没有索引,不能使用普通的for循环遍历,没有带索引的方法

注意

  • TreeSet、HashSet集合是无序的集合:存储和取出元素的顺序有可能不一致。
  • LinkedSet是有序的集合。

各种集合类的特点

集合类重要程度特点
ArrayList重点底层是数组实现的,查询快,增删慢
LinkedList一般底层是链表实现的,查询慢,增删快
Vector了解底层是数组实现的,查询快,增删慢
HashSet重点底层是哈希表+(红黑树)实现的,无索引,不可以存储重复元素,存取无序
LinkedHashSet一般底层是哈希表+链表实现的,无索引,不可以存储重复元素,可以保证存取顺序
TreeSet了解底层是二叉树实现,一般用于排序

集合常用方法

Java.util.Collection接口:

Collection接口是所有单列集合的最顶层的接口,里面定义了所有单列集合共性的方法。

任意的单列集合都可以使用Collection接口中的方法。

共性的方法:

方法名称含义
public boolean add(E e);把给定的对象添加到当前集合中
public void clear();清空集合中的所有的元素
public boolean remove(E e);把指定的对象在当前集合中删除
public boolean contains(E e);判断当前集合中是否包含给定的对象
public boolean isEmpty();判断当前集合是否为空
public int size();返回集合中元素的个数
public Object[] toArray();把集合中的元素,存储到数组当中
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;

public class ListandSet {
    public static void main(String[] args) {
        //创建集合对象,使用了多态
        Collection<String> coll = new ArrayList<>();
        System.out.println(coll);//[],打印出来的不是地址值,重写了toString方法

        //add(E e)方法,返回的是booolean类型的值,一般为true,不用接收
        boolean b1 = coll.add("James");
        System.out.println("b1: " + b1);
        System.out.println(coll);//[James]
        coll.add("Durant");
        coll.add("Curry");
        coll.add("Davis");
        coll.add("Irving");
        System.out.println(coll);//[James, Durant, Curry, Davis, Irving]

        //remove(E e)方法,返回值是boolean类型。
        // 集合中存在该元素,则删除元素,返回true,否则,删除失败,返回false
        boolean b2 = coll.remove("Irving");
        System.out.println("b2:" + b2);//true
        boolean b3 = coll.remove("Harden");
        System.out.println("b3:" + b3);//false
        System.out.println(coll);//[James, Durant, Curry, Davis]

        //contains(E e)方法,判断当前集合中是否包含给定的对象
        //包含,返回true;不包含,返回false
        boolean b4 = coll.contains("Giannis");
        System.out.println("b4:" + b4);//false
        boolean b5 = coll.contains("James");
        System.out.println("b5:" + b5);//true

        //isEmpty()方法,返回boolean值,判断该集合是否为空
        boolean b6 = coll.isEmpty();
        System.out.println("b6:" + b6);//false

        //size()方法,返回int值,该集合的长度
        int l = coll.size();
        System.out.println("l:" + l);

        //toArray()方法,返回的是Object[]
        Object[] array = coll.toArray();
        System.out.println(array[2]);//Curry

        //clear()方法,清空集合中所有的元素,但是不删除集合,集合还存在
        coll.clear();
        System.out.println(coll);//[]


    }
}

Iterator迭代器

Iterator接口

迭代是Collection集合元素的通用获取方式。在取元素之前要先判断集合中有没有元素,如果有,就把这个元素取出来,继续再判断,如果还有就要再取出来。一直到把集合中的所有元素全部取出。这种取出方式专业术语成为迭代。

Iterator接口的常用方法如下:

  • public E next():返回迭代的下一个元素
  • public boolean hasNext():如果仍有元素可以迭代,则返回true。

Iterator迭代器是一个接口,我们无法直接使用,需要使用Iterator接口的实现类对象。

获取实现类对象的方法比较特殊。

Collection接口中有一个方法,叫做iterator(),这个方法返回的就是迭代器的实现类对象。

  • Iterator iterator() 返回在此 collection 的元素上进行迭代的迭代器

迭代器使用步骤:

  1. 先使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)
  2. 使用Iterator接口中的方法hasNext()判断还有没有下一个元素
  3. 使用Iterator接口中的方法next()取出集合中的下一个元素
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Iterator02 {
    public static void main(String[] args) {
        //多态  接口  =  实现类对象
        Collection<Integer> coll = new ArrayList<>();
        coll.add(8);
        coll.add(8);
        coll.add(4);
        coll.add(8);
        System.out.println(coll);
        //多态  接口  =  实现类对象
        Iterator<Integer> iterator = coll.iterator();
        //使用实现类对象的hasNext()方法判断是否还有元素
        while(iterator.hasNext()){
            //使用实现类对象的next()方法取出元素
            System.out.println(iterator.next());
        }
    }
}

迭代器的实现原理

在coll调用iterator()方法的时候,返回了Iterator类型的实现类对象iterator,并且把指针(索引)指向集合的-1索引。

iterator对象调用hasNext()方法,判断集合中还有下一个元素。

iterator对象调用next()方法,做了两件事情:

  1. 取出下一个元素
  2. 把指针向后移动一位

增强for循环

增加for循环(也称for each循环)是JDK 1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作。

格式:

for(元素的数据类型  变量:Collection集合or数组){
    //写操作代码
}

它用于遍历Collection和数组。通常只进行遍历元素,不要在遍历的过程中对集合元素进行增删操作。

Collection extends Iterable: 所有的单列集合都可以使用增强for;

public interface Iterable:实现这个借口允许对象成为"foreach"语句的目标。

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

public class ReforceFor {
    public static void main(String[] args) {
        demo01();
        demo02();
    }

    //使用增强for循环遍历数组
    public static void demo01() {
        int[] arr = {1, 2, 3};
        for (int i : arr) {
            System.out.println(i);
        }

    }

    //使用增强for循环遍历集合
    public static void demo02() {
        Collection<Integer> collection = new ArrayList<>();
        collection.add(8);
        collection.add(8);
        collection.add(4);
        collection.add(8);
        for (int a : collection) {
            System.out.println(a);
        }

    }
}

泛型

泛型的概念

泛型是一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型。

泛型也可以看出是一个变量,用来接收数据类型。

  • E e:Element 元素
  • T t: Type 类型

ArrayList集合在定义的时候,不知道集合中都会存储什么类型的数据,所以类型使用泛型。

创建集合对象的时候,就会确定泛型的数据类型。

使用泛型的好处

创建集合对象,不使用泛型。

好处:

  • 集合不使用泛型,默认的类型就是Object类型,可以存储任意类型的数据。

弊端:

  • 不安全,会引起异常
public class Element01 {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("abc");
        list.add(2);

        //使用迭代器遍历list集合
        //获取迭代器
        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            //取出的元素也是Object类型的
            Object obj = iterator.next();
            System.out.println(obj);

            //想要使用String类型特有的方法length获取字符串的长度,不能使用 多态 Object obj = "abc";
            //需要向下转型
            //会抛出ClassCastException类型转换异常,不能把Integer类型转换为String类型
            String s = (String) obj;
            System.out.println(s.length());
        }
    }
}

创建集合对象,使用泛型。

好处:

  • 1.避免了类型转换的麻烦,存储的是什么类型,取出的就是什么数据类型
  • 2.把运行期异常(代码运行之后才会抛出的异常),提前到了编译期(写代码的时候就会抛出异常)

弊端:

  • 泛型是什么类型,就只能存储什么类型的数据

定义和使用含有泛型的类

定义一个含有泛型的类。

泛型是一个未知的数据类型,当我们不确定使用什么数据类型的时候,可以使用泛型。

泛型可以接受任意的数据类型,可以是Integer,String,Student…

创建对象的时候确定泛型的数据类型。

public class GenericClass<E> {
    private E name;

    public GenericClass() {

    }

    public E getName() {
        return name;
    }

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

    public GenericClass(E name) {
        this.name = name;
    }
}
public class GenericClassTest {
    public static void main(String[] args) {
        //创建GenericClass对象,泛型使用Integer类型
        GenericClass<Integer> gc1 = new GenericClass<>();
        gc1.setName(2);
        int i = gc1.getName();//自动拆箱
        System.out.println(i);

        //创建GenericClass对象,泛型使用String类型
        GenericClass<String> gc2 = new GenericClass<>();
        gc2.setName("小明");
        String name = gc2.getName();
        System.out.println(name);
    }

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

泛型定义在方法的修饰符和返回值类型之间。

格式:

修饰符 <泛型> 返回值类型 方法名(参数列表(使用泛型)){

​ 方法体;

}

含有泛型的方法,在调用方法的时候确定泛型的数据类型。

传递什么类型的参数,泛型就是什么类型。

public class GenericMethod {
    //定义一个含有泛型的方法
    public <M> void method01(M m){
        System.out.println(m);
    }
    //定义一个含有泛型的静态方法
    public static <S> void method02(S s){
        System.out.println(s);
    }
}
public class GenericMethodTest {
    public static void main(String[] args) {
        GenericMethod gm = new GenericMethod();
        //调用含有泛型的方法,传递什么类型,泛型就是什么类型
        gm.method01(1);
        gm.method01(true);
        gm.method01("22");
        gm.method01(6.5);

        GenericMethod.method02("静态方法");
        GenericMethod.method02(9.7);
        GenericMethod.method02(88);
    }
}

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

含有泛型的接口,第一种定义方法:定义接口的实现类,实现接口,指定接口的泛型。

如:

public interface Iterator {

​ E next();

}

Scanner类实现了Iterator,并指定接口的泛型为String,所以重写的next()方法,泛型默认为String类:

public final class Scanner implements Iterator{

​ next(String str);

}

public interface GenericInterface<I> {
    public abstract void method(I i);
}
public class GenericInterfaceImpl implements GenericInterface<String> {
    @Override
    public void method(String s) {
        System.out.println(s);

    }
}
public class GenericInterfaceTest {
    public static void main(String[] args) {
        GenericInterfaceImpl gi1 = new GenericInterfaceImpl();
        gi1.method("只能是字符串");//只能是字符串
    }
}

含有泛型的接口,第二种定义方法:接口使用什么泛型,实现类就是用什么泛型,类跟着接口走,就相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型。

如:

public interface List{

​ boolean add(E e);

​ E get(int index);

}

public class ArrayList implements List{

​ boolean add(E e);

​ E get(int index);

}

public interface GenericInterface<I> {
    public abstract void method(I i);
}
public class GenericInterfaceImpl2<I> implements GenericInterface<I> {
    @Override
    public void method(I i) {
        System.out.println(i);
    }
}
public class GenericInterfaceTest {
    public static void main(String[] args) {
        GenericInterfaceImpl2<Integer> gi2 = new GenericInterfaceImpl2<>();
        gi2.method(88);//88
    }
}

泛型通配符

当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。

此时只能接受数据,而不能往该集合中存储数据。

使用方法:

  • 不能创建对象使用;
  • 只能作为方法的参数使用
import java.util.ArrayList;
import java.util.Iterator;

public class Generic01 {
    public static void main(String[] args) {
        ArrayList<String> list01 = new ArrayList<>();
        list01.add("a");
        list01.add("b");
        ArrayList<Integer> list02 = new ArrayList<>();
        list02.add(6);
        list02.add(7);
        printArrayList(list01);
        printArrayList(list02);

    }
    public static void printArrayList(ArrayList<?> list){
        for(Object a : list){
            System.out.println(a);
        }
    }
}
通配符的高级使用——受限泛型
  • 泛型的上限限定:? extends E 代表使用的泛型必须是E类型的子类/本身
    泛型的下限限定:? super E 代表使用的泛型必须是E类型的父类/本身
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值