修炼完这一篇秘籍,你就可以成为四段斗之气战士了,天赋出色者甚至可以越阶战斗,成为百里挑一的斗者,踏上漫漫强者路,拳打北山幼儿园,脚踢南海敬老院。
该系列文章上一篇: 三段斗之气–Java集合框架概述.
该系列文章下一篇: 五段斗之气–Collection的子接口:List接口.
初遇Collection
Collection接口是List、Set和Queue接口的父接口,该接口里定义的方法既可用于操作List集合,也可用于操作Set和Queue集合。JDK没有提供Collection接口的任何直接实现,而是提供了更具体地子接口。在Java5之前,Java集合把所有对象都当成Object类型处理,从JDK5.0增加了泛型以后,Java集合就可以记住容器中对象的数据类型了。通过一棵接口继承数可以很直观清晰的了解到我们需要关注的内容。
初看上去光实现类就有六个,其实搞清楚它们各自之间的性能特点,行为区别之后,就不会再觉得难以记忆了,况且在日常开发中最常用的往往就是那特定几个类的特定方法,并没有多么复杂。弄清楚一些关键问题也可以帮助自己记忆,比如Vector、ArrayList、LinkedList的异同点是什么?Set和List的区别是什么?这些问题在后面内容中都会详细的进行分析。
Collection接口的常用斗技方法
Collection接口是一种集合的行为规范,它里面定义了一些接口方法,凡是继承或者实现了该接口的类和接口,都必须具备和它一样的行为规范,因此可以先研究一下Collection接口中定义的方法,看它具备哪些功能,换言之也就是先对List接口和Set接口有哪些共有的方法进行研究,后面再一层层具体看每个子接口下面每个具体类有哪些独有的功能。
常用方法 | 方法声明 |
---|---|
添加 | add(Object obj) add(Collection coll) |
存储个数 | int size():注意获取的不是集合的总大小,而是存储的有效元素个数 |
清空集合 | void clear() |
是否为空 | boolean isEmpty() |
是否包含 | boolean 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) |
获取哈希值 | hashCode() |
遍历 | iterator:返回迭代器对象,用于集合遍历 |
这些方法都是在日常开发中比较常用的,因此有必要对每个方法进行测试,这里选择使用ArrayList作为具体的实现类来对Collection接口中的方法进行测试,代码编译环境是JDK1.8。
package com.learnjiawa.jihe;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* Collection接口中声明的方法的测试
*
* 结论:
* 向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals().
*
* @author shkstart
* @create 2019 上午 10:04
*/
public class CollectionTest {
@Test
public void test1(){
//创建一个Arraylist类,用Collection规范它的行为
Collection coll = new ArrayList();
// ArrayList coll1 = new ArrayList(); //coll和coll1的行为有区别
coll.add(123);
coll.add(456);
Person p = new Person("Jerry",20);
coll.add(p);
coll.add(new Person("Jerry",20));
coll.add(new String("Tom"));
coll.add(false);
//1.contains(Object obj):判断当前集合中是否包含obj
//我们在判断时会调用obj对象所在类的equals()。
// boolean contains = coll.contains(123);
// System.out.println(contains);
// System.out.println(coll.contains(new String("Tom")));
// System.out.println(coll.contains(p));//true
System.out.println(coll.contains(new Person("Jerry",20)));//false -->true
/*
* 如果不重写Person类中的equals方法,上面会返回false,因为默认的equals方法里面是用“==”
* 比较的对象地址,而重新new的person对象很明显地址不相同,所以返回false
* 如果判断是否包含p,就算不重写equals方法也会返回true,因为p引用本来就指向的同一个地址
* */
//2.containsAll(Collection coll1):判断形参coll1中的所有元素是否都存在于当前集合中。
Collection coll1 = Arrays.asList(123,4567);
System.out.println(coll.containsAll(coll1));
}
@Test
public void test2(){
//3.remove(Object obj):从当前集合中移除obj元素。
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry",20));
coll.add(new String("Tom"));
coll.add(false);
coll.remove(1234);
System.out.println(coll);
coll.remove(new Person("Jerry",20));
System.out.println(coll);
//4. removeAll(Collection coll1):差集:从当前集合中移除coll1中所有的元素。
Collection coll1 = Arrays.asList(123,456);
coll.removeAll(coll1);
System.out.println(coll);
}
@Test
public void test3(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry",20));
coll.add(new String("Tom"));
coll.add(false);
//5.retainAll(Collection coll1):交集:获取当前集合和coll1集合的交集,并返回给当前集合
// Collection coll1 = Arrays.asList(123,456,789);
// coll.retainAll(coll1);
// System.out.println(coll);
//6.equals(Object obj):要想返回true,需要当前集合和形参集合的元素都相同。
Collection coll1 = new ArrayList();
coll1.add(456);
coll1.add(123);
coll1.add(new Person("Jerry",20));
coll1.add(new String("Tom"));
coll1.add(false);
System.out.println(coll.equals(coll1));
}
@Test
public void test4(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry",20));
coll.add(new String("Tom"));
coll.add(false);
//7.hashCode():返回当前对象的哈希值
System.out.println(coll.hashCode());
//8.集合 --->数组:toArray()
Object[] arr = coll.toArray();
for(int i = 0;i < arr.length;i++){
System.out.println(arr[i]);
}
//拓展:数组 --->集合:调用Arrays类的静态方法asList()
List<String> list = Arrays.asList(new String[]{"AA", "BB", "CC"});
System.out.println(list);
List arr1 = Arrays.asList(new int[]{123, 456});
System.out.println(arr1.size());//1
List arr2 = Arrays.asList(new Integer[]{123, 456});
System.out.println(arr2.size());//2
//9.iterator():返回Iterator接口的实例,用于遍历集合元素。放在IteratorTest.java中测试
}
}
Iterator迭代器接口
- Iterator对象称为迭代器(设计模式的一种),主要用于遍历Collection集合中的元素。
- GOF(写设计模式的四大金刚)给迭代器的定义为:提供一个方法访问一个容器(container)对象中各个元素,-而又不需暴露该对象的内部细节。迭代器模式,就是为容器而生。类似于“公交车上的售票员”,“火车上的乘务员”、“空姐”。题外话,在编程的世界里,设计模式的地位和数据结构、算法差不多,甚至于要更加高深,它属于天阶功法,可遇而不可求,我们了解知道就行了,初学者甚至工作经验只有一两年的斗师强者都完全没必要专门去深究这个功法,无它,太高深了,你以为你会了,其实你没有,但一些常见的用法套路还是要熟练的。
- Collection接口继承了java.lang.Iterable接口,该接口有一个iterator()方法,那么所有实现了Collection接口-的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象。
- Iterator仅用于遍历集合,Iterator本身并不提供承装对象的能力。如果需要创建Iterator对象,则必须有一个被迭代的集合。
- 集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前
对Collection中的迭代器方法进行代码测试。
package com.learnjiawa.jihe;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* 集合元素的遍历操作,使用迭代器Iterator接口
* 1.内部的方法:hasNext() 和 next()
* 2.集合对象每次调用iterator()方法都得到一个全新的迭代器对象,
* 默认游标都在集合的第一个元素之前。
* 3.内部定义了remove(),可以在遍历的时候,删除集合中的元素。此方法不同于集合直接调用remove()
*/
public class IteratorTest {
@Test
public void test1(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry",20));
coll.add(new String("Tom"));
coll.add(false);
Iterator iterator = coll.iterator();
//方式一:
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// //报异常:NoSuchElementException
// System.out.println(iterator.next());
//方式二:不推荐
// for(int i = 0;i < coll.size();i++){
// System.out.println(iterator.next());
// }
//方式三:推荐
hasNext():判断是否还有下一个元素
while(iterator.hasNext()){
//next():①指针下移 ②将下移以后集合位置上的元素返回
System.out.println(iterator.next());
}
}
@Test
public void test2(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry",20));
coll.add(new String("Tom"));
coll.add(false);
//错误方式一:跳着输出并且报异常
// Iterator iterator = coll.iterator();
// while((iterator.next()) != null){
// System.out.println(iterator.next());
// }
//错误方式二:
//集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。
while (coll.iterator().hasNext()){
System.out.println(coll.iterator().next());
}
}
//测试Iterator中的remove()
//如果还未调用next()或在上一次调用 next 方法之后已经调用了 remove 方法,
// 再调用remove都会报IllegalStateException。
@Test
public void test3(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry",20));
coll.add(new String("Tom"));
coll.add(false);
//删除集合中"Tom"
Iterator iterator = coll.iterator();
while (iterator.hasNext()){
// iterator.remove();
Object obj = iterator.next();
if("Tom".equals(obj)){
iterator.remove();
// iterator.remove();
}
}
//遍历集合
iterator = coll.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
注意:
- 在调用it.next()方法之前必须要调用it.hasNext()进行检测。若不调用,且下一条记录无效,直接调用it.next()会抛出NoSuchElementException异常。
- Iterator可以删除集合的元素,但是是遍历过程中通过迭代器对象的remove方 法,不是集合对象的remove方法。
- 如果还未调用next()或在上一次调用 next 方法之后已经调用了 remove 方法,再调用remove都会报IllegalStateException。
除了使用迭代器遍历集合外,还可以使用增强for来遍历集合,增强for的优点是不需要获取所遍历集合或着数组的长度,不需要使用索引访问元素,更加简洁。
去看该系列文章下一篇: 五段斗之气–Collection的子接口:List接口.
参考文献
[1]Bruce Eckel.Java编程思想(第4版)[M].机械工业出版社,2008:459-524.
更多
对我的文章感兴趣,持续更新中…