Collection

Collection集合是所有单值存储方式的超级接口,所以在实例化对象的时候要使用它的实现子类。

Collection c = new ArrayList();

Collection集合常用方法

  • boolean add(E e):向集合中添加元素;
  • int size():获取集合的元素个数;
  • void clear():清空集合;
  • boolean contains(Object o):查看集合是否包含o元素;
  • boolean isEmpty():集合中元素个数是否为空,是返回true;
  • boolean remove(Object o):删除集合中某个元素(如果存在);
  • Object[] toArray():将集合转成数组;
  • Iterator iterator():返回该集合的迭代器。
package com.dh.collection;

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

public class Collection01 {

    public static void main(String[] args) {
        Collection c = new ArrayList();
        //添加元素
        System.out.println("添加元素......");
        c.add(1);   //基本数据类型有自动装箱
        c.add(2.2);
        c.add('3');
        c.add(true);
        c.add("hello kitty");
        c.add(new Collection01());
        
        //打印集合c
        //因为ArrayList的抽象父类AbstractCollection重写了toString(),所以输出的不是引用,而是真正的值
        System.out.println("直接打印集合c:"+c);

        //获取集合中的元素个数
        int size = c.size();
        System.out.println("集合中的元素个数为:"+size);

        //判断集合中是否包含某个元素
        System.out.println("集合中是否包含1:"+c.contains(1));
        System.out.println("集合中是否包含false:"+c.contains(false));

        //移除集合中的某个元素
        c.remove('3');
        //再次获取集合中的长度
        System.out.println("此时集合中的元素个数为:"+c.size());

        //将集合转成数组
        System.out.println();
        System.out.println("将集合转换成数组,并且遍历输出:");
        Object[] array = c.toArray();
        for (Object o : array) {
            //因为基本数据类型的包装类和String都重写了toString(),所以输出的不是引用。
            //但Collection01没有重写,所以输出的是引用。
            System.out.println(o+"\t");
        }
        System.out.println();

        //判断集合是否为空
        System.out.println("集合是否为空:"+c.isEmpty());
        System.out.println("清空元素......");
        c.clear();
        System.out.println("集合是否为空:"+c.isEmpty());
    }
}

结果:

添加元素......
直接打印集合c:[1, 2.2, 3, true, hello kitty, com.dh.collection.Collection01@6e8dacdf]
集合中的元素个数为:6
集合中是否包含1:true
集合中是否包含false:false
此时集合中的元素个数为:5
    
将集合转换成数组,并且遍历输出:
1	
2.2	
true	
hello kitty	
com.dh.collection.Collection01@38082d64		//因为没有重写toString()

集合是否为空:false
清空元素......
集合是否为空:true

Process finished with exit code 0

contains()和remove()源码简单分析

先来看一个例子:

package com.dh.collection;

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

public class Collection02 {

    public static void main(String[] args) {

        Collection c = new ArrayList();

        String s1 = new String("hello");
        String s2 = new String("kitty");
        c.add(s1);
        c.add(s2);
        String s3 = new String("hello");
        //没有往c中添加s3
        System.out.println(c.contains(s3));
    }
}

结果:

true

虽然我们没有把s3添加到c中,s1和s3也的的确确是不同的两个对象,c是集合,存储的也是数据的引用,那为什么c包含s3的结果是true呢?难道是只看值吗?

我们可以去看看源码:

 int indexOfRange(Object o, int start, int end) {
     Object[] es = elementData;
     if (o == null) {
         for (int i = start; i < end; i++) {
             if (es[i] == null) {
                 return i;
             }
         }
     } else {
         for (int i = start; i < end; i++) {
             if (o.equals(es[i])) {
                 return i;
             }
         }
     }
     return -1;
 }

可以看到:contains()实际上是调用了equals()来进行比较是否相等,而String中又重写了equals(),所以比较的实际上就是"hello"。

(remove()同理,底层调用的也是equals()进行元素的判断。)

迭代器

上述中的iterator方法还没有讲到,现在就来说一下~

上篇文章的继承图中讲到Collection接口继承了Iterable接口,Iterable接口中有一个iterator(),返回值为Iterator接口,这个就是我们遍历集合所需要的迭代器对象啦!Iterator接口中有两个用于遍历集合元素的方法:

(Collection及其子类都通用~)

  • boolean hasNext():判断是否还有元素;
  • E next():将下一个元素返回。

package com.dh.iterator;

import com.dh.collection.Collection01;

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

public class IteratorDemo01 {

    public static void main(String[] args) {
        //创建一个集合
        Collection c = new ArrayList();
        //添加元素
        c.add(1);  
        c.add(2.2);
        c.add('3');
        c.add(true);
        c.add("hello kitty");
        c.add(new IteratorDemo01());

        //获取迭代器
        Iterator iterator = c.iterator();
        //遍历元素
        while(iterator.hasNext()){
            Object o = iterator.next();	//此时的o还是Object类型
            System.out.println(o);	//这里输出的o为String类型
        }
    }
}

结果:

1
2.2
3
true
hello kitty
com.dh.iterator.IteratorDemo01@6e8dacdf

注意:当集合的结构发生变化时,要重新的获取迭代器。

迭代器对象在生成时,相当于指向了当前集合的一个快照,在获取迭代器之后改变集合的结构,当前的迭代器对象是无法获取新的集合的,所以会报错。

如:

package com.dh.iterator;

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

public class IteratorDemo02 {

    public static void main(String[] args) {
        //创建一个集合
        Collection c = new ArrayList();
        //获取迭代器
        Iterator iterator = c.iterator();
        //添加元素
        c.add(1);

        //遍历元素
        while(iterator.hasNext()){
            Object o = iterator.next();
            System.out.println(o);
        }
    }
}

结果:会报java.util.ConcurrentModificationException,因为获取迭代器之后又改变了集合的结构。

Exception in thread "main" java.util.ConcurrentModificationException
	at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042)
	at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996)
	at com.dh.iterator.IteratorDemo02.main(IteratorDemo02.java:19)

Collection集合中的remove()和Iterator接口中的remove()的区别

如果我们想在遍历集合时删掉某一个元素,就相当于改变了集合的结构,所以肯定是会报上述的java.util.ConcurrentModificationException的异常的,所以Iterator也给我们提供了一个remove()方法,使用Iterator的remove()删除元素就不会改变集合的结构,也就不会因为集合结构改变没有获取新的迭代器而报异常了。

//获取迭代器
Iterator iterator = c.iterator();
//遍历元素
while(iterator.hasNext()){
    Object o = iterator.next();
    System.out.println(o);
    iterator.remove();  //删除当前迭代器指向的元素
}
posted @ 2021-02-09 00:16  deng-hui  阅读(195)  评论(0编辑  收藏  举报