Java高级编程--集合概述+Collection集合+Iterator迭代器

面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象的操作,就要对对象进行存储。使用Array数组存储对象方面具有 一些弊端,而Java集合就像一种容器,可以动态地把多个对象的引用放入容器中。集合是Java学习过程中非常重要得一个知识点,也是面试时高频的问题之一。


目录:

☍ Java集合框架概述

☍ Collection接口

☍ Iterator迭代器接口


☍ Java集合框架概述

▴ 数组 VS 集合

➢ 数组和集合的特点

·集合、数组都是对多个数据进行存储操作的结构,简称Java容器。此时的存储主要是指内存层面的存储,不涉及硬盘持久化的存储

➢ 数组在内存存储方面的特点

  ·数组初始化以后,长度就确定了

  ·数组声明的类型,就决定了进行元素初始化时的类型,之后只能操作指定类型的数据

➢ 数组在存储数据方面的弊端

  ·数组初始化以后,长度就不可变了,不便于扩展

  ·数组中提供的属性和方法少,不便于进行添加、删除、插入等操作,且效率不高

  ·无法直接获取存储元素的个数(非数组长度)

  · 数组存储的数据是有序的、可以重复的,对于无序、不可重复的需求不能满足

➢ 集合储存数据的特点

  · Java 集合类可以用于存储数量不等的多个对象,还可用于保存具有映射关系(key-value)的关联数组

➢ 集合的使用场景

▴ Java集合的分类

Java 集合可分为 Collection 和 Map 两种体系

➢ Collection接口: 存储单列数据,定义了存取一组对象的方法的集合

· List:元素有序、可重复的集合

· Set:元素无序、不可重复的集合

➢ Map接口: 双列数据,保存具有映射关系“key-value对”的集合

➢ Collection接口继承树

✑ JDK提供的集合API位于java.util包内

➢ Map接口继承树

 |--Collection接口:单列集合,用来存储一个一个的对象
*   > --List接口:存储有序的、可重复的数据     动态“数组”,可替换常规数组使用
*      ◌ ArrayList、LinkedList、Vector
*   > --Set接口:存储无序的、不可重复的数据
*      ◌ HashSet、LinkedHashSet、ThreeSet
*|--Map接口:双列集合,用来存储成对的数据(key-value映射关系)
*      ◌ HashMap、LinkedHashMap、TreeMap、Hashtable、properties

☍ Collection接口

▴ Collection接口概述

♪ Collection接口是List、Set和Queue接口的父接口,该接口里定义的方法
既可用于操作Set集合,也可用于操作List和Queue集合。

♪ JDK不提供此接口的任何直接实现,而是提供更具体的子接口(如:Set和List)
实现。

♪ 在Java5之前,Java集合会丢失容器中所有对象的数据类型,把所有对象都当成Object类型处理;从JDK 5.0增加了泛型以后,Java 集合可以记住容器中对象的数据类型,可通过对象的强制转换恢复对象的类型。

▴ Collection接口方法

➻ 添加

◌ add(Object obj)

◌ addAll(Collection coll)

➻ 获取有效元素的个数

◌ int size()

➻ 获取有效元素的个数

◌ void clear()

➻ 是否是空集合

◌ boolean isEmpty()

➻ 是否包含某个/某些元素

◌ contains(Object obj):通过元素的equals方法来判断是否是同一个对象,从而判断集合是否包含该元素

◌ boolean containsAll(Collection c):拿两个集合的元素挨个比较,也是调用元素的equals方法来比较的,即判断目标集合是否是当前集合的子集

➻ 删除

◌ boolean remove(Object obj):通过元素的equals方法找到要删除的元素,只会删除找到的第一个元素

◌ boolean removeAll(Collection coll):删除当前集合中存在的所有目标集合的元素,即去除两个集合的交集部分,取集合的差集

➻ 取两个集合相同的元素

◌ boolean retainAll(Collection c):即取两个集合的交集,把交集的结果存在当前集合中,不影响集合c

➻ 判断两个集合是否相等

◌ boolean equals(Object obj)

➻ 将集合转换为数组

◌ Object[] toArray():集合转换的数组是Object类型,如果知道元素类型可以对取得的元素强制转换;支持泛型toArray(T t)

◌ 数组转换为集合为: Arrays.asList(arr),转换后的集合不可添加,删除或清空元素,否则报UnsupportedOperationException异常

➻ 获取集合对象的哈希值

◌ hashCode()

➻ 遍历集合

◌ iterator():返回迭代器对象,用于集合遍历

✯ 注: 向Collection接口的实现类的对象中添加Object对象数据时,一般要求该Object所在类要重写equals()方法,否则在使用类似contains()方法时比较的就是地址值(相当于使用==比较),而非内容了

@Description: 测试Collection接口中的方法(一)

/**
  * ۵ size();   获取集合中的元素数量
  * ۵ add(E e); 将元素e添加到集合中,E为泛型或object
  * ۵ addAll(Collection col):将另一个Collection集合的元素添加到当前集合中
  * ۵ isEmpty():判断当前集合元素是否为空  注:isEmpty()判断的是当前集合元素个数是否为0
  * ۵ remove(Object o) 若集合中存在元素o,则移除匹配到的第一个元素o,若不存在则不操作
  * ۵ removeAll(Collection col):移除两个集合中所有的交集部分
  * ۵ clear():清空集合元素,非null
  * ۵ contains(Object obj): 判断当前集合中是否包含obj
  * ۵ containsAll(Collection col):判断集合col1是否包含另一个集合col2,即col2是否是col1的子集
**/
public void testCollectionMethod1() {
    Collection coll = new ArrayList();
    System.out.println("--------size()、add(E e)-----)");
    //add(Object e)  支持泛型:将元素e添加到集合中
    coll.add(new String("ab"));
    coll.add("cd");
    coll.add(123);   //自动装箱 int --> Integer
    coll.add(new Date());
    coll.add(new Animal("人类"));
    coll.add(new Person("Jone",32));
    //size():获取集合元素数量
    System.out.println("coll集合元素数量:" + coll.size());  //4
    for (Object o : coll) {
        System.out.println("coll集合元素:" + o);
    }
    System.out.println();

    System.out.println("--------addAll(Collection coll)-----)");
    //addAll(Collection col):将另一个Collection集合的元素添加到当前集合中
    coll.addAll(coll);
    System.out.println("coll集合元素数量:" + coll.size());  //8
    for (Object o : coll) {
        System.out.println("coll集合元素:" + o);
    }
    System.out.println();
    Collection list = new ArrayList(12);
    System.out.println(list.size());  //0
    list.add(235); //list.size()=1
    //说明:size()是指元素数量,而传入的参数是底层数组的长度,要与数组长度区分

    System.out.println("--------isEmpty()判空-----)");
    //isEmpty():判断当前集合元素是否为空  注:isEmpty()判断的是当前集合元素个数是否为0
   System.out.println("coll集合元素是否为空:" + coll.isEmpty());  //false
   System.out.println();

   System.out.println("--------remove(Object obj)/removeAll()-----)");
   //remove(Object o) 若集合中存在元素o,则移除匹配到的第一个元素o,若不存在则不操作
   System.out.println("集合coll是否移除ABC:"+coll.remove("ABC"));
   System.out.println("移除集合中存在的第一个值为ABC的元素:\n" + coll.toString());
   //String类型的对象使用equals比较的是内容
   System.out.println("集合coll是否移除new String(ab):"+coll.remove(new String("ab")));
   System.out.println("移除集合中存在的第一个值为ab的元素:\n" + coll.toString());
   //自定义类的对象实现的是Object的equals,使用的是==,比较的是对象地址值,在remove时使用new对象作为参数无法找到集合中内容对应的元素
   System.out.println("是否移除new Animal(人类):"+coll.remove(new Animal("人类")));
   //重写自定义类中的equals方法,判断内容是否相等,此时remove()就可以找到集合中内容相同的对象
   System.out.println("是否移除new Person('Jone',32):"+coll.remove(new Person("Jone",32)));
   //removeAll(Collection col):移除两个集合中所有的交集部分
   Collection coll2 = new ArrayList();
   coll2.add("ef");
   coll2.add(123);
   coll2.add("cd");
   System.out.println("是否移除coll和coll2所有公共元素:"+coll.removeAll(coll2));
   System.out.println("移除coll和coll2所有公共元素:\n" + coll.toString());
   System.out.println();

   System.out.println("--------clear()清空元素-----)");
   //clear():清空集合元素,非null,list.size()=0
   coll.clear();
   System.out.println("coll集合clear后是否为空:" + coll.isEmpty());  //true
   System.out.println();

   Collection col1 = new ArrayList();
   col1.add(114);
   col1.add(new String("Hello"));
   col1.add(new Double(3.14));
   col1.add("world");
   col1.add(false);
   col1.add(new Animal("人类"));
   col1.add(new Person("Tom",21));

   System.out.println("-----contains(Object obj)/containsAll(Collection col)");
   //contains(Object obj): 判断当前集合中是否包含obj
   boolean isContain = col1.contains("world");
   System.out.println("集合col1是否包含new String('Hello'):" + col1.contains(new String("Hello")));
   //true,String此时比的不是对象地址是否相同,而是内容是否相同
   System.out.println("集合col1是否包含world:" + isContain);  //true
   System.out.println("判断集合是否包含new的自定义Animal对象:"+col1.contains(new Animal("人类")));
   //false   自定义类若没有重写类的equals()默认继承Object,此时是使用==比的是对象地址值
   System.out.println("判断集合是否包含new的自定义对象Person:"+col1.contains(new Person("Tom",21)));
   //true     自定义类重写类的equals(),可定义为按内容比较

   //containsAll(Collection col):判断集合col1是否包含另一个集合col2,即col2是否是col1的子集
   Collection col2 = new ArrayList();
   col2.add(114);
   col2.add("world");
   System.out.println("集合col1是否包含集合coll2:"+col1.containsAll(coll2));  //false
   System.out.println("集合col1是否包含集合col2:"+col1.containsAll(col2));   //true
}

@Description: 测试Collection接口中的方法(二)

/**
  *  ۵ retainAll(col2):获取两个集合的相同元素(交集)返回到col1集合,与removeAll相反(去除两个集合的相同元素/交集)
  *  ۵ equals:判断两个集合是否相等,其中自定义类要求重写equals,
  *      对于有序集合,要求两个集合不仅元素内容要相等,元素的位置也要相等,有序性
  *  ۵ hashCode():输出对象的哈希值
  *  ۵ toArray():将集合转换为Object类型数组    Arrays.asList(Object obj1...):数组转换为集合
  *  ۵ toArray(T t):支持泛型
**/
public void testCollectionMethod2(){
    Collection col = new ArrayList();
    col.add(123);
    col.add(345);
    col.add(new Animal("人类"));
    col.add(new Person("Army",20));
    col.add("az");
    col.add(false);

    System.out.println("---------retainAll(Collection col)-------");
    //col1.retainAll(col2):获取两个集合的相同元素(交集)返回到col1集合,与removeAll相反(去除两个集合的相同元素/交集)
    Collection col2 = Arrays.asList(123,345,"az",new Person("Army",20));
    System.out.println(col.toString());
    System.out.println(col.retainAll(col2));
    System.out.println(col.toString());
    System.out.println();

    System.out.println("---------equals(Object obj)---------");
    //equals:判断两个集合是否相等,其中自定义类要求重写equals,
    // 对于如ArrayList的有序集合,要求两个集合不仅元素内容要相等,元素的位置也要相等,有序性
    System.out.println("col:"+col.toString()+"\ncol2:"+col2.toString());
    System.out.println("集合col1是否与col2相等:"+col.equals(col2));   //true 集合Collection也是Object的子类
    Collection col3 = Arrays.asList(345,123,"az",new Person("Army",20));
    System.out.println("col2:"+col2.toString()+"\ncol3:"+col3.toString());
    System.out.println("集合col2是否与col3相等:"+col2.equals(col3));   //false  有序集合的元素顺序也要相同才返回true
    System.out.println();

    System.out.println("---------hashCode()---------");
    //hashCode():输出对象的哈希值
    System.out.println("集合col的hash值:"+col.hashCode());   //161818
    System.out.println();

    System.out.println("---------toArray()---------");
    //toArray():将集合转换为Object类型数组
    Object objs[] = col.toArray();
    for (Object obj : objs) {
        System.out.println(obj);
    }
    //Arrays.asList(Object obj1...):数组转换为集合
    Object objs2[] = new Object[]{"ABC",13,54.3,new String("中国"),new Person("小莉",26)};
    List col4 = Arrays.asList(objs2);  //List为Collection的子类
    System.out.println("数组转换为集合:"+col4);
    System.out.println();
    
    try {
        col4.add("hello");// 报UnsupportedOperationException异常,后面讲数组与集合的转换再讲具体原因
        //col4.remove("ABC");
        //col4.clear();
        System.out.println("col4 集合:" + col4);
        //总结:使用asList将数组转换为集合,可查找,比较等,不可以添加、删除、清空
    }catch (UnsupportedOperationException e){
        e.printStackTrace();
    }
}

✯ 注:使用asList将数组转换为集合,可查找,比较等,不可以添加、删除、清空


☍ Iterator迭代器接口

♫ Iterator对象称为迭代器(设计模式的一种),主要用于遍历 Collection集合中的元素,不能用来遍历map集合。

♫ GOF给迭代器模式的定义为:提供一种方法访问一个容器(container)对象中各个元
素,而又不需暴露该对象的内部细节。迭代器模式,就是为容器而生。

♫ Iterator仅用于遍历集合,Iterator本身并不存储对象。如果需要创建Iterator 对象,则必须有一个被迭代的集合。

♫ 集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。

➢ Iterator接口实现的方法

方法:boolean hasNext()
说明: 如果迭代集合具有更多的元素,则返回true。即next()返回一个元素而非抛出异常,则返回true
结果:如果迭代具有更多元素返回true,否则返回false
总结:判断是否还有下一个元素
方法:E next()
说明: 返回迭代中的下一个元素
结果:迭代中的下一个元素,支持泛型
异常:若迭代没有更多的元素抛出NoSuchElementException异常
总结:指针后移,访问该位置元素内容
方法:default void remove()
说明: 从底层集合中删除此迭代器返回的最后一个元素(最后调用next()方法返回的元素)(可选操作)。调用一次next()后只能调用一次remove()方法。如果底层集合在迭代过程中以任何方式进行修改而不是通过调用此方法,则迭代器的行为是未指定的。即不能在使用迭代器遍历集合时直接操作集合元素
结果:迭代中的下一个元素,支持泛型
异常:如果remove操作不被这个迭代器支持时抛出Unsupported OperationException异常
如果next方法未被调用或在一次next方法后多次使用remove方法则抛出IllegalStateException异常
如果迭代遍历过程可修改集合元素内容,但删除、添加、清空等操作会报ConcurrentModificationException异常
总结:在遍历时移除当前指针位置集合中的元素
方法:default void forEachRemaining(Consumer<? super E> action)
说明: 对每个剩余元素执行给定的操作,知道所有元素都被处理或动作引发异常。如果指定了该顺序,则按迭代的顺序执行操作。动作抛出的异常被转发给呼叫者
结果:迭代中的下一个元素,支持泛型
异常:如果指定的动作action为空,报NullPointerException异常
特殊要求:从JDK1.8版本开始支持此方法

✯ 注: 在调用it.next()方法之前必须要调用it.hasNext()进行检测。若不调用,且下一条记录无效,直接调用it.next()会抛出NoSuchElementException异常。

♫ forEachRemaining()用法

public void testForEachRemaining(){
   ArrayList col = new ArrayList();
   col.add(new String("ab"));
   col.add(123);   //自动装箱 int --> Integer (自动向上转型) --> Object
   col.add(new Person("Jone",32));
   col.add(false);
   Iterator iterator1 =  col.iterator();
   System.out.println("++++++++++++++++++++");
   System.out.println(iterator1.next());
   System.out.println(iterator1.next());
   System.out.println("--------------------");
   //操作迭代器中剩余部分
   iterator1.forEachRemaining(ele -> changeEle(ele));
}

public void changeEle(Object e){
   System.out.println(e);
}


/*  输出
    ++++++++++++++++++++
	ab
	123
	--------------------
	Person{name='Jone', age=32}
	false
*/

▴ 循环遍历集合元素的三种方式

♫ Collection实现类有get()方法可以通过下标索引获取元素,可以使用for循环或while循环遍历集合(不推荐)。

public void printListMethod1(){
    List list = new ArrayList();
    list.add("123");
    list.add("hello");
    list.add(new Date());
    for (int i = 0; i < list.size(); i++) {
       System.out.println(list.get(i));
    }
}

♫ java 5.0 提供了foreach循环迭代访问Collection和数组,此时遍历操作不需获取Collection或数组的长度,无需使用索引访问元素。

public void printListMethod2(){
    List list = new ArrayList();
    list.add("123");
    list.add("hello");
    list.add(new Date());
    for (Object o : list) {
       System.out.println(o);
    }
}

♫ 使用Iterator迭代器或ListIterator迭代器遍历集合。

public void printListMethod3(){
    List list = new ArrayList();
    list.add("123");
    list.add("hello");
    list.add(new Date());
    Iterator iterator = list.iterator();
    while (iterator.hasNext()){
        Object obj = iterator.next();
        System.out.println(obj);
    }
}

♫ Iterator遍历集合的两种错误写法。

public void errIteratorMethod(){
    Collection col = new ArrayList();
    col.add(new String("ab"));
    col.add(123);   //自动装箱 int --> Integer (自动向上转型) --> Object
    col.add(new Person("Jone",32));
    col.add(null);
    System.out.println(col.toString());

    Iterator iterator = col.iterator();
    //错误方式一:
    //while(iterator.next() != null){
     /*
      三个错误:
        1、当遍历到最后一个元素时,再调用next()方法报NoSuchElementException异常
        2、判断中执行一次next(),输出中又执行一次next(),会导致隔行输出,如输出第1,3,5...个元素
        3、如果集合中有null元素,会导致null元素后的元素无法输出
       结果:隔行输出,NoSuchElementException异常
     */
      //    System.out.println(iterator.next());
     //}

     //错误方式二:
    while (col.iterator().hasNext()){
       //错误原因:每次执行都创建一个新的匿名Iterator对象
       //结果:死循环,且输出的都是集合中第一个元素
       System.out.println(col.iterator().next());
    }
}

✯ 注:一个迭代器对象只能从头到尾遍历一次(游标指向最后且不会自动回退),不能重复循环遍历,即遍历完集合的所有元素后需从新使用iterator()方法获取新的迭代器对象。

➢ ListIterator接口

♫ ListIterator迭代器的使用基本和Iterator迭代器一致,只是补充了一些方法。

public void testListIterator(){
        List list = new ArrayList();
        list.add("123");
        list.add("hello");
        list.add(new Date());
        Iterator iterator = list.iterator();
        while (iterator.hasNext()){
            Object obj = iterator.next();
            System.out.println(obj);
        }

        System.out.println("------------");
        ListIterator iterator1 = list.listIterator();
        System.out.println(iterator1.previousIndex());
        System.out.println(iterator1.nextIndex());
        System.out.println("是否存在下一个元素:" +iterator1.hasNext());
        System.out.println("获取下一个元素:" + iterator1.next());
        System.out.println("获取下一个元素:" + iterator1.next());
        System.out.println("是否存在上一个元素:" + iterator1.hasPrevious());
        System.out.println("获取上一个元素:" + iterator1.previous());
        System.out.println("获取上一个元素:" + iterator1.previous());
        System.out.println("上一个元素的索引:" + iterator1.previousIndex());
        System.out.println("下一个元素的索引:" + iterator1.nextIndex());
        //添加元素:添加在当前索引位置添加元素,当前位置元素及后面元素下标后移
        iterator1.add("China");
        System.out.println(iterator1.next());
        iterator1.previous();
        //删除元素:删除当前位置元素,后面元素下标前移
        iterator1.remove();
        iterator1.add("Java Web");

        ListIterator iterator2 = list.listIterator();
        System.out.println("------------------");
        while (iterator2.hasNext()){
            System.out.println(iterator2.nextIndex() + " : " + iterator2.next());
        }
    }

下图仅为个人理解

✯ 简单理解为iterator.remove()删除集合元素时,删除的为rmove前next()返回的元素;iterator.add()添加元素为在当前索引位置添加元素,当前元素及其之后的元素后移

✯ iterator.next()是先返回游标位置的下一个元素,然后游标后移;iterator.previous()是先返回游标所在位置元素,然后游标前移。所以接连使用iterator.next()和iterator.previous()一次返回的元素才会相同。

做一个小测试✍

public void test(){
 	List list = new ArrayList();
    list.add(123);
    list.add("hello");
    list.add(new Date());

    ListIterator iterator = list.listIterator();
    System.out.println(iterator.nextIndex());    //输出:0  -> 游标初始话
    System.out.println(iterator.next());         //输出:123  -> 游标后移 指向0
    System.out.println(iterator.nextIndex());    //输出:1
    System.out.println(iterator.next());         //输出:hello  -> 游标后移 指向1
    System.out.println(iterator.previousIndex());//输出:1
    System.out.println(iterator.previous());     //输出:hello  -> 游标前移 指向0
    System.out.println(iterator.nextIndex());    //输出:1
    System.out.println(iterator.next());         //输出:hello  -> 游标后移 指向1
}

本博客与CSDN博客༺ཌ༈君☠纤༈ད༻同步发布

Hi~
posted @ 2021-01-01 21:57  ༺ཌ༈君☠纤༈ད༻  阅读(396)  评论(0编辑  收藏  举报