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(); //删除当前迭代器指向的元素
}