Java 之 Collection 接口

一、Collection 集合

   Collection:单列集合类的根接口,用于存储一系列符合某种规则的元素,它有两个重要的子接口,分别是 java.util.List 和 java.util.Set。

   List 的特点是 元素有序、元素可重复。主要实现类有 java.util.ArrayList 和 java.util.LinkedList。

   Set 的特点是 元素无序、而且不可重复。主要实现类有 java.util.HashSet 和 java.util.TreeSet。

   下面通过一张图来描述整个 Collection 集合类的基础体系。

    

 

   其中,红色的为 接口,其他的为具体的实现类。

二、collection集合的常用方法

   Collection 是所有单列集合的父接口,因此在 Collection 中定义了单列集合(List 和 Set)通用的一些方法,这些方法可用于操作所有的单列集合。

   常用方法:

    1、添加元素

add(Object obj):添加元素对象到当前集合中
addAll(Collection other):添加other集合中的所有元素对象到当前集合中,即this = this ∪ other

     注意:如果 add(Collection c) 会把集合 c 作为一个整体添加到原集合中。

    2、删除元素

boolean remove(Object obj) :从当前集合中删除第一个找到的与obj对象equals返回true的元素。
boolean removeAll(Collection coll):从当前集合中删除所有与coll集合中相同的元素。即this = this - this ∩ coll

    3、判断元素

boolean isEmpty():判断当前集合是否为空集合。
boolean contains(Object obj):判断当前集合中是否存在一个与obj对象equals返回true的元素。
boolean containsAll(Collection c):判断c集合中的元素是否在当前集合中都存在。即c集合是否是当前集合的“子集”。

    4、其他

int size():获取当前集合中实际存储的元素个数
boolean retainAll(Collection coll):当前集合仅保留与c集合中的元素相同的元素,即当前集合中仅保留两个集合的交集,即this  = this ∩ coll;
Object[] toArray():返回包含当前集合中所有元素的数组
void clear():清空当前集合
Iterator iterator():获取遍历当前集合的迭代器对象

三、Collection 集合的遍历

  1、通过 toArray() 方法

    通过 Collection 的 toArray() 方法,先返回数组,然后遍历数组

  2、Iterator 迭代器遍历

    (1)Iterator 接口

      因为Collection接口继承了java.lang.Iterable接口,该接口有一个iterator()方法,那么所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,该对象可以用于迭代集合中的元素。

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

      常用方法:

boolean hasNext():如果仍有元素可以迭代,则返回 true
Object next():返回迭代的下一个元素。
void remove():从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。

      注意:

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

      ② 如果还未调用next()或在上一次调用 next 方法之后已经调用了 remove 方法,再调用remove都会报IllegalStateException

       图解

                     

        

        

           

        Demo:

 1 @Test
 2     public void test(){
 3         Collection c = new ArrayList();  //使用多态,创建对象
 4         c.add(new Student(1,"张三"));
 5         c.add(new Student(2,"李四"));
 6         c.add(new Student(3,"王五"));
 7         c.add(new Student(4,"赵六"));
 8         c.add(new Student(5,"钱七"));
 9         
10         Iterator iterator = c.iterator();    //获取迭代器
11         while(iterator.hasNext()){           // 判断是否有迭代元素
12             Student next = (Student) iterator.next(); // 取出迭代元素
13             //例如:要删除学号为1的学生对象
14             if(next.getId()==1){
15                 iterator.remove();
16             }
17         }
18     }

     Tips:在进行集合元素取出时,如果集合中已经没有元素了,还继续使用迭代器的 next 方法,将会发生 java.util.NoSuchElementException 没有集合元素的异常。

    (2)迭代器的实现原理

      遍历的步骤:

      (1)调用集合的 Iterator() 方法获得迭代器对象

      (2)使用 hashNext() 方法判断集合中是否存在下一个元素

      (3)如果存在,则调用 next() 方法将元素取出;否则说明已经到达了集合末尾,停止遍历元素

         Iterator 迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素,下来通过一个图来演示 Iterator 对象迭代元素的过程。

        (1)在调用 next 方法前,迭代器的索引位于第一个元素之前,即索引为 -1 的位置,不执行任何元素。

    (2)当第一次调用迭代器的 next 方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回

    (3)当再次调用 next 方法时,迭代器的索引会指向第二个元素并将该元素返回,依次类推,直到 hasNext 方法返回 false,表示到达了集合的末尾,终止对元素的遍历。  

  3、foreach 遍历(增强 for)

     Java 5时Collection接口继承了java.lang.Iterable接口,因此Collection系列的集合就可以直接使用foreach循环遍历。

    增强 for 循环(for each循环)是JDK 1.5 以后出来的一个高级 for 循环,专门用来遍历数组和集合的。

    它的内部原理其实是个 Iterator 迭代器,所有在遍历的过程中,不能对集合中的元素进行增删操作。

    语法格式

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

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

     Demo:

1 public class Demo{
2     public static void main(String[] args) {
3         int[] arr = {3,5,6,87};
4            //使用增强for遍历数组
5         for(int a : arr){//a代表数组中的每个元素
6             System.out.println(a);
7         }
8     }
9 }

 四、扩展

  1、当自己创建一个动态数组类或容器,可以使用 foreach 遍历吗?

    foreach 底层是使用了 Iterator 迭代器。所以需要把当前类实现 Iterable 接口,然后实现iterator() 方法。

   Iterator 也是一个接口,它的实现类,通常在集合(容器) 类中使用内部类实现,并在 iterator() 方法中创建它的对象。

   Demo:

 1 public class MyArrayList implements Iterable{ 
 2     //实现迭代器
 3     @Override
 4     public Iterator iterator() {
 5         return new MyItr();
 6     }
 7     // 私有化的内部类
 8     private class MyItr implements Iterator{
 9         private int cursor;//游标
10 
11         @Override
12         public boolean hasNext() {
13             System.out.println("还有下一个");
14             return cursor!=total;
15         }
16 
17         @Override
18         public Object next() {
19             System.out.println("拿到下一个");
20             return data[cursor++];
21         }
22         
23     }
24 }    

  2、思考:如果遍历数组,什么情况下选用foreach,什么情况下选用for循环?

    ① 当如果操作中涉及到 【下标】操作时,用for最好

    ② 当只是查看元素的内容,那么选 foreach 更简洁一些

  3、思考:如果遍历Collection系列集合,什么情况下选用foreach,是否能选用 for 循环?

    首先考虑使用foreach,如果该集合也有索引信息的话,也可以通过for来操作,如果没有下标的信息,就不要用for。即,如果该集合的物理结构是数组的,那么可以用for,如果物理结构是链式,那么使用下标操作效率很低。

  4、思考:如果遍历Collection系列集合,什么情况下选用foreach,什么情况下使用Iterator?

    ① 如果只是查看集合的元素,使用foreach,代码会更简洁。

    ② 但是如果要涉及到在遍历集合的同时根据某种条件要删除元素等操作,那么选用Iterator。

原文地址:https://www.cnblogs.com/niujifei/p/11435089.html