02_Java语音进阶||day02_Collection、Iterator迭代器、增强for、泛型

第一章 Collection集合

1.1 集合概述

  1. 集合:是Java中提供的一种容器,可以用来存储多个数据
  2. 集合和数组都是容器,区别:
    1. 数组长度固定的,集合的长度是可变
    2. 数组中存储的是同一类型的元素,可以存储基本数据类型的值和对象集合只能存储对象,而且对象的类型可以不一致。在开发中一般当对象多的时候,使用集合进行存储。
        int[] arr = new int[10];    //基本数据类型
        Student[] stu = new Student[3]; //对象
    

1.2 集合的框架

  • 学习集合的目标:
    1. 会使用集合存储数据
    2. 会遍历集合,把数据取出来
    3. 掌握每种集合的特性
  • 集合框架的学习方式:
    1. 学习顶层:学习顶层结构/抽象类中共性的方法,所有的子类都可以使用
    2. 使用底层:顶层不是借口就是抽象类,无法创建对象使用,需要使用底层的子类创建对象使用
  1. List接口:Vector,ArrayList,LinkedList
    1. 有序的集合(存储和取出元素顺序相同)
    2. 允许存储重复的元素
    3. 索引,++可以使用普通的for循环++遍历
  2. Set接口:TessSet,HashSet|LinkedHashSet
    1. 有序无序都有:
      1. TessSet和HashSet——>无序集合(存储和取出元素顺序不一定相同)
      2. LinkedHashSet——>有序集合
    2. 不允许存储重复的元素
    3. 没有索引,++不能使用普通的for循环++遍历
  3. Collection接口:List和Set两个子接口
    1. 定义的是所有单列集合共性的方法
    2. 所有的单列集合都可以使用共性的方法
    3. 没有带索引的方法
  • 注:继承–>子类共性抽取,形成父类(接口)

1.3 Collection集合

  1. 单列集合的体系结构:
  • List
    • ArrayList:底层是数组实现的,查询快,增删慢
    • LinkedList:底层是链表实现的,查询慢,增删快
  • Set
    • HashSet:底层是哈希表+(红黑树)实现的,无索引,不可以存储重复元素,存取无序
    • LinkedHashSet:底层是哈希表+链表实现的,无索引,不可以存储重复的元素,可以保证存取顺序【!】
    • TreeSet:底层是二叉树实现的,一般用于排序
  1. Collection集合常用的方法
    • boolean add(E e);
      • 向集合中添加元素
          Collection<String> coll = new ArrayList<>();
          coll.add("Hello");
          coll.add("World");
          coll.add("Java");
          System.out.println(coll);   //[Hello, World, Java]
      
    • boolean remove(E e);
      • 删除集合中的某个元素
          Collection<String> coll = new ArrayList<>();
          coll.add("Hello");
          coll.add("World");
          coll.add("Java");
          boolean result = coll.remove("Hello");
          System.out.println(result); //true
          System.out.println(coll);   //[World, Java]
      
    • void clear();
      • 清空集合所有元素,不删除集合
          Collection<String> coll = new ArrayList<>();
          coll.add("Hello");
          coll.add("World");
          coll.add("Java");
          coll.clear();
          System.out.println(coll);   //[]
      
    • boolean contains(E e);
      • 判断集合中是否包含某个元素
          Collection<String> coll = new ArrayList<>();
          coll.add("Hello");
          coll.add("World");
          coll.add("Java");
          boolean result = coll.contains("Java");
          System.out.println(result); //true
          boolean result1 = coll.contains("Demo");
          System.out.println(result1); //false
      
    • boolean isEmpty();
      • 判断集合是否为空
          Collection<String> coll = new ArrayList<>();
          coll.add("Hello");
          coll.add("World");
          coll.add("Java");
          boolean result = coll.isEmpty();
          System.out.println(result); //false
      
    • int size();
      • 获取集合的长度
          Collection<String> coll = new ArrayList<>();
          coll.add("Hello");
          coll.add("World");
          coll.add("Java");
          int size = coll.size();
          System.out.println(size);   //3
      
    • Object[] toArray();
      • 把集合中的元素,存储到数组中
          Collection<String> coll = new ArrayList<>();
          coll.add("Hello");
          coll.add("World");
          coll.add("Java");
          Object[] obj = coll.toArray();
          //如果不是数组不能使用Arrays.toString方法
          System.out.println(Arrays.toString(obj));   //[Hello, World, Java]
      

1.4 Collection集合常用功能

  1. (API)Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。
  2. java.util.Collection接口
    1. 所有单利集合的最顶层接口,里面定义所有单利集合共性方法,任意的单利集合都可以使用Collection接口中的方法
  3. 共性的方法:
    public static void main(String[] args) {
        //创建集合对象
        Collection<String> coll = new ArrayList<>();
        System.out.println(coll);   //[]——>重写了toString方法

        //add——返回值boolean,一般都是true,所以不用写
        boolean b1 = coll.add("张三");
        System.out.println("b1:" + b1); //b1:true
        coll.add("李四");
        coll.add("王五");
        coll.add("赵六");
        coll.add("田七");
        System.out.println(coll);   //[张三, 李四, 王五, 赵六, 田七]

        //remove——返回值boolean,存在元素删除,返回true
        boolean b2 = coll.remove("赵六");
        System.out.println("b2=" + b2); //b2=true
        boolean b3 = coll.remove("赵四");
        System.out.println("b3=" + b3); //b3=false
        System.out.println(coll);   //[张三, 李四, 王五, 田七]

        //contains——boolean,包含返回true
        boolean b4 = coll.contains("李四");
        System.out.println("b4=" + b4); //b2=true
        boolean b5 = coll.contains("赵四");
        System.out.println("b5=" + b5); //b2=true

        //isEmpty——boolean,为空返回true
        boolean b6 = coll.isEmpty();
        System.out.println("b6:" + b6); //b6:false

        //size——返回集合中元素的个数
        int size = coll.size();
        System.out.println("size:" + size); //size:4

        //toArray——把集合中的元素,存储到数组中
        Object[] arr = coll.toArray();
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " "); //张三 李四 王五 田七
        }
        System.out.println();

        //clear——清空集合元素
        coll.clear();
        System.out.println(coll);   //[]
        System.out.println(coll.isEmpty()); //true
    }
    
    //结果:
    []
    b1:true
    [张三, 李四, 王五, 赵六, 田七]
    b2=true
    b3=false
    [张三, 李四, 王五, 田七]
    b4=true
    b5=false
    b6:false
    size:4
    张三 李四 王五 田七 
    []

第二章 Iterator迭代器

2.1 Iterator接口

  1. 迭代的产生:
    • 在程序开发中,经常需要遍历集合中的所有元素。(例如Set集合无索引:不能使用普通的for循环遍历)
    • 针对这种需求,JDK专门提供了一个接口
    • 通用的取出集合中元素的方式,不管哪个集合,都可以用迭代器取出元素
  2. 迭代的概念:(取出方式专业术语:迭代)
    1. 迭代对Collection集合元素的通用获取方式
      • 取元素之前先判断有没有元素,如果有就取出来,在判断有没有元素,一直把所有的元素取出来。
    2. 遍历的过程中,不能对集合中的元素进行增删改查
  3. java.util.Iterator接口:迭代器(对集合进行遍历)
    1. 两个常用的方法:hasNext,next
      1. boolean hasNext()——(判断还有没有一个元素)
        • 如果仍有元素可以迭代,则返回 true。
      2. E next()——(取出集合中的一个元素)
        • 返回迭代的下一个元素。
    2. 获取实现类的方式:(Collection接口中的iterator方法)
      • Iterator迭代器,是一个接口,我们无法直接使用它,需要使用Iterator接口的实现类对象。
      • Collection接口中有一个方法,叫iterator(),这个方法返回的就是迭代器的实现类对象
      • Iterator iterator()
        • 返回在此 collection 的元素上进行迭代的迭代器。
    3. 迭代器的使用步骤【重点】
      1. 使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)
      2. 使用Iterator接口中的方法hasNext判断还有没有下一个元素
      3. 使用Iterator接口中的方法next取出集合中的下一个元素(并且将指针移动一位

2.2 Iterator的代码实现

  • 注:Iterator接口也是泛型的,迭代器的泛型跟着集合走,集合是什么泛型,迭代器就是什么泛型
  • 注:没有元素,再取元素(next):会抛出NOSuchElementException没有元素异常
  1. 通过2.1步骤发现,迭代器取出元素是一个重复的过程,所以可以用循环优化
    • 不知道集合中有多少元素,所以使用while循环
    • 循环条件:hasNext方法返回false
        //创建一个集合对象
        Collection<String> coll = new ArrayList<>();
        //添加元素
        coll.add("姚明");
        coll.add("库里");
        coll.add("詹姆斯");
        coll.add("科比");
        coll.add("乔丹");
        
        //1. 使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)
        //左边接口,右边实现类对象
        Iterator<String> it = coll.iterator();
        while(it.hasNext()){
            String e = it.next();
            System.out.println(e);
        }
    
    • for循环作为了解
      • 因为next()方法不仅取下一个元素(并且将指针移动一位)
        for(Iterator<String> it2 = coll.iterator(); it.hasNext;){
            String e = it.next();
            System.out.println(e);
        }
    

2.3 Iterator的实现原理

2.4 增强for循环

  1. 增强for循环(也称为for each循环),是JDK1.5以后出现的一个高级for循环
    • 快捷方式:集合/数组名.for
  2. 专门用来遍历数组和集合的【重点】。它的内部原理其实是一个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删改查【!】
    • 必须有被遍历的目标,目标只能是Collection集合和数组
  3. public interface Collectionextends Iterable
    • 所有的单利集合都可以使用增强for
  4. 格式:
        for(集合/数组的数据类型 变量名 : 集合/数组名){
            //循环体语句;
        }
    
    public class Demo02Foreach {
        public static void main(String[] args) {
            //使用增强for遍历数组
            demo01();   //1 2 3 4 5
            System.out.println();
    
            //使用增强for遍历集合
            doem02();   //aaa bbb ccc ddd
        }
    
        //使用增强for遍历数组
        private static void demo01() {
            int[] arr = {1, 2, 3, 4, 5};
            for(int i : arr){
                System.out.print(i + " ");
            }
        }
    
        //使用增强for遍历集合
        private static void doem02() {
            ArrayList<String> listA = new ArrayList<>();
            listA.add("aaa");
            listA.add("bbb");
            listA.add("ccc");
            listA.add("ddd");
            for(String s : listA){
                System.out.print(s + " ");
            }
        }
    }

2.5 迭代器&增强for总结

  1. 迭代器&增强for的初衷
    • 随着集合学习的增加,List接口下有索引还是可以使用for循环的,但是Set接口中有无索引的,就不能使用for循环了。——>所以提供了通用的遍历方式
      • Iterater迭代器遍历——>集合
      • 增强for循环遍历——>集合,数组
    public static void main(String[] args) {
        Collection<String> coll = new ArrayList<>();
        coll.add("Hello");
        coll.add("World");
        coll.add("Java");

        //使用迭代器遍历集合
        Iterator<String> it = coll.iterator();
        while (it.hasNext()){
            String s = it.next();
            System.out.print(s + " ");
        }
        System.out.println();
        System.out.println("=========");

        //使用增强for循环遍历集合
        for(String a : coll){
            System.out.print(a + " ");
        }
        System.out.println();
        System.out.println("=========");

        //使用增强for循环遍历数组
        int[] arr = {1, 2, 3, 4, 5};
        for(int b : arr){
            System.out.print(b + " ");
        }
    }
    
    //结果:
    Hello World Java 
    =========
    Hello World Java 
    =========
    1 2 3 4 5 

第三章 泛型

3.1 泛型的概念

  1. 泛型:
    1. 可以看成一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型。
    2. 也可以看成是一个变量,可以接收任意的数据类型
        E e:Element元素
        T t:Type类型
    
  2. 例:ArrayList集合在定义的时候,不知道集合中会存储什么类型的数据,所以使用泛型。
    1. ArrayList集合中泛型的应用
          public class ArrayList<E> {
              public boolean add(E e) {}
              public E get(int index) {}
          }
      
      • E:未知的数据类型
    2. 创建集合对象的使用,就会确定泛型的数据类型
          ArrayList<String> listA = new ArrayList<>();
      
    3. 这时候E就被确定为String
          public class ArrayList<String> {
              public boolean add(String e) {}
              public String get(int index) {}
          }
      

3.2 使用泛型的好处

  1. 创建集合对象,不使用泛型:
    1. 好处:
      • 集合不使用泛型,默认的类型就是Object类型,可以存储任意类型的数据
    2. 弊端:
      • 集合不安全,会引发异常
    • 例:
        public class Demo01Generic {
            public static void main(String[] args) {
                show01();
            }
        
            //创建集合对象,不使用泛型
            private static void show01() {
                ArrayList listA = new ArrayList();
                listA.add("abc");
                listA.add(1);
        
                //使用迭代器遍历listA集合
                Iterator it = listA.iterator();
                while (it.hasNext()){
                    //取出元素也是Object类型
                    Object arr = it.next();
                    System.out.print(arr + " ");    //abc 1
        
                    //想要使用String特有的length方法,多态Object arr = "abc";
                    //需要向下转型
                    //会抛出ClassCastException类型转换异常,不能把Integer类型转换为String类型
                    String s = (String)arr;
                    System.out.println(s);
                }
            }
        }
    
    • 注:多态的弊端:不能使用子类特有的方法(需要向下转型)
  2. 创建集合对象,使用泛型:
    1. 好处:
      1. 避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型
      2. 把运行期异常(代码运行之后会抛出的异常),提示到了编译期(写代码的时候会抛出的异常)
    2. 弊端:
      • 泛型是什么类型,就只能存储什么类型的数据
    • 例:
        public class Demo01Generic {
            public static void main(String[] args) {
                show02();
            }
        
            //创建集合对象,使用泛型
            private static void show02() {
                ArrayList<String> listB = new ArrayList();
                listB.add("abc");
                listB.add("bcd");
        
                Iterator<String> it = listB.iterator();
                while (it.hasNext()){
                    String arr = it.next();
                    System.out.print(arr + "->" + arr.length() + " ");
                }
            }
        }
        
        //结果:
        abc->3 bcd->3
    

3.3 定义与使用含有泛型的类

  1. 定义格式:
    • <>里面的E,其实写什么都行
        public class 类名称<E> {
            private E 成员变量名;
    
            public E getName() {
                return 成员变量名;
            }
        
            public void setName(E 成员变量名) {
                this.成员变量名 = 成员变量名;
            }
        }
    
  2. 定义一个含有泛型的类:(模拟ArrayList集合)
    //定义一个泛型类:GenericCalss.java
    public class GenericClass<E> {
        private E name;
    
        public E getName() {
            return name;
        }
    
        public void setName(E name) {
            this.name = name;
        }
    }

    //主方法:Demo01GenericCalss.java
    public static void main(String[] args) {
        //不写泛型,默认是Object类型
        GenericClass gc = new GenericClass();
        gc.setName("不使用泛型只能是字符串");
        Object name = gc.getName();
        System.out.println(name);   //不使用泛型只能是字符串

        //创建对象,泛型使用Integer类型
        GenericClass<Integer> gc1 = new GenericClass<>();
        gc1.setName(234);
        Integer name1 = gc1.getName();
        System.out.println(name1);  //234

        //创建对象,泛型使用String类型
        GenericClass<String> gc2 = new GenericClass<>();
        gc2.setName("String类型的泛型");
        String name2 = gc2.getName();
        System.out.println(name2);  //String类型的泛型
    }
    
    //结果:
    不使用泛型只能是字符串
    234
    String类型的泛型

3.4 定义与使用含有泛型的方法

  1. 泛型定义在方法的位置:
    1. 普通方法:修饰符和返回值类型之间
    2. 静态方法:static和返回值类型之间
      • 方法调用的时候用类名.方法名调用
  2. 定义格式:
        修饰符 <泛型> 返回值类型 方法名 (参数(使用泛型)){
            方法体;
        }
    
  3. 含有泛型的方法,在调用泛型方法的时候,确定泛型的数据类型
    • 传递的什么类型,泛型就是什么类型
    //定义一个含有泛型方法的类:GenericMethod.java
    public class GenericMethod {
        //定义一个含有泛型的方法
        public <M> M method01(M m){
            return m;
        }
    
        //定义一个含有泛型的静态方法
        public static <M> void method02(M m){
            System.out.println(m);
        }
    }
    //主方法:Demo03GenericMethod.java
    public static void main(String[] args) {
        //创建一个对象
        GenericMethod gm = new GenericMethod();

        //调用泛型方法method01
        System.out.println(gm.method01(10));
        System.out.println(gm.method01(2.2));
        System.out.println(gm.method01(true));
        System.out.println(gm.method01("abcd"));
        System.out.println("============");

        GenericMethod.method02(20);
        GenericMethod.method02("jjj");
    }
    
    //结果:
    10
    2.2
    true
    abcd
    ============
    20
    jjj

3.5 定义与使用含有泛型的接口

  1. 定义格式:
    public interface 接口名<I> {
        public abstract void 方法名(I i);
    }
    
  2. 使用方法:
    1. 定义接口的实现类,实现接口,并且指定接口的泛型
      • 不指定默认是Object
          public class 实现类名 implements 接口名<直接指定泛型类型>
      
    2. 【常用】接口使用什么泛型,实现类就使用什么泛型,实现类跟着接口走
      • 就相当于定义了一个含有泛型的类——创建对象的时候确定泛型
          public class 实现类名<泛型> implements 接口名<泛型>
      
    //定义的接口
    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 GenericInterfaceImpl2<I> implements GenericInterface<I>{
    
        @Override
        public void method(I i) {
            System.out.println(i);
        }
    }
    
    //主方法
    public static void main(String[] args) {
        //创建GenericInterfaceImpl对象
        GenericInterfaceImpl gi1 = new GenericInterfaceImpl();
        gi1.method("abc");

        //创建GenericInterfaceImpl2对象
        GenericInterfaceImpl2<Integer> gi2 = new GenericInterfaceImpl2<>();
        gi2.method(234);

    }
    
    //结果:
    abc
    234

3.6 泛型通配符

  1. 当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示
    • 一旦使用了泛型通配符,只能使用Object类中的共性方法,集合中元素自身方法无法使用。
  2. 通配符的基本使用
    1. 不知道使用什么类型接收【重点】的时候,此时可以使用?,?表示未知通配符
      • 此时只能接收数据,不能往集合中存储数据
  3. 使用方式:
    1. 不能创建对象使用
    2. 只能作为方法的参数使用
  • 注:泛型没有继承概念的
    • ArrayList listA = new ArrayList(); //错
    public class Demo05Generic {
        public static void main(String[] args) {
            ArrayList<Integer> listA = new ArrayList<>();
            listA.add(1);
            listA.add(2);
    
            ArrayList<String> listB = new ArrayList<>();
            listB.add("abc");
            listB.add("def");
    
            printArray(listA);
            printArray(listB);
        }
    
        //定义一个方法可以遍历所有类型的ArrayList集合
        //这时候我们不知道ArrayList集合使用的什么数据类型,可以使用泛型的?通配符来接收数据
    
        public static void printArray(ArrayList<?> list){
            //使用迭代器遍历集合
            Iterator<?> it = list.iterator();
            while (it.hasNext()){
                Object next = it.next();
                System.out.print(next + " ");
            }
        }
    }
    
    //结果:
    1 2 abc def

3.7 泛型通配符高级使用—受限泛型(了解)

  1. 之前设置泛型的时候,实际上是可以任意设置的,只要是类就可以设置。
    • 但是在Java的泛型中,可以指定一个泛型的上限和下限
  2. 泛型的上限
    1. 格式:
        类型名称 <? extends 类> 对象名称
    
    1. 意义:
      • 只能接收该类型及其子类
  3. 泛型的下限
    1. 格式:
        类型名称 <? super 类> 对象名称
    
    1. 意义:
      • 只能接收该类型及其父类型
  4. 对比:
    1. 泛型的上限限定:? extends E
      • 代表使用的泛型只能是E类型的子类/本身
    2. 泛型的下限限定:? super E
      • 代表使用的泛型只能是E类型的父类/本身

3.8 泛型的总结

第四章 集合总和案例

4.1 案例介绍

4.2 案例分析

  1. 工具类Collections类中的shuffle方法——会随机打乱集合中元素的顺序
    • static void shuffle(List<?> list)
      • 使用指定的随机源对指定列表进行置换

4.3 案例实现

    /*
    斗地主
        1.  准备牌
        2.  洗牌
        3.  发牌
        4.  看牌
     */
    public static void main(String[] args) {
        //1.准备牌
        //定义一个ArrayList集合,泛型用String
        ArrayList<String> poker = new ArrayList<>();
        //定义两个数字,一个存储花色,一个存储牌序号
        String[] colors = {"♠", "♥", "♣", "♦"};
        String[] numbers = {"2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3"};
        //先把大王小王存储到poker集合中
        poker.add("大王");
        poker.add("小王");
        //用增强for循环嵌套遍历两个数字组合成52张牌
        for (String color : colors) {
            for (String number : numbers) {
                //System.out.println(color + number);
                //把组装的牌存到poker集合中
                poker.add(color + number);
            }
        }

        //2.洗牌(工具类Collections类中的shuffle方法)
        Collections.shuffle(poker);

        //3.发牌(定义四个集合:玩家的牌和底牌)
        ArrayList<String> palyer01 = new ArrayList<>();
        ArrayList<String> palyer02 = new ArrayList<>();
        ArrayList<String> palyer03 = new ArrayList<>();
        ArrayList<String> diPai = new ArrayList<>();

        //遍历poker集合,获取每一张牌
        //使用poker的索引%3给三个玩家轮流发牌
        //剩余三张给底牌
        //注:先判断底牌(i >= 51),否则没牌了
        for (int i = 0; i < poker.size(); i++) {
            //获取每一张牌
            String p = poker.get(i);
            if(i >= 51){//发底牌
                diPai.add(p);
            }else if(i % 3 == 0){//给玩家一
                palyer01.add(p);
            }else if(i % 3 == 1){//给玩家二
                palyer02.add(p);
            }else if(i % 3 == 2){//给玩家三
                palyer03.add(p);
            }
        }

        //4.看牌
        System.out.println("刘德华的牌:" + palyer01);
        System.out.println("周润发的牌:" + palyer02);
        System.out.println("周星驰的牌:" + palyer03);
        System.out.println("底牌牌:" + diPai);
    }
    
    //结果:
    刘德华的牌:[♣Q, ♥3, ♥10, ♣3, ♥8, ♠10, ♠9, ♥Q, ♠Q, ♠A, ♦3, ♦8, ♦9, ♠4, ♠5, ♦10, ♠2]
    周润发的牌:[♥6, 大王, ♥4, 小王, ♥2, ♦2, ♥9, ♥5, ♣10, ♣A, ♦5, ♦4, ♠8, ♦A, ♦J, ♥A, ♦Q]
    周星驰的牌:[♥K, ♠6, ♠K, ♣7, ♥J, ♣K, ♣2, ♣5, ♣J, ♠7, ♦6, ♠J, ♦K, ♦7, ♣4, ♥7, ♠3]
    底牌牌:[♣6, ♣8, ♣9]
发布了42 篇原创文章 · 获赞 6 · 访问量 1137

猜你喜欢

转载自blog.csdn.net/qq_40572023/article/details/104523060
今日推荐