Collection接口和List接口
正式讲课之前,我们先来搞明白三个小问题:
- 为什么需要集合类?
很多情况下,我们需要对一组对象进行操作。而且很可能事先并不知道到底有多少个对象。为了解决这个问题呢,Java 就提供了集合类供我们使用。
- 集合类的特点
a. 只能存储引用数据类型
b. 可以自动地调整自己的大小
- 数组和集合类都是容器,它们有何不同?
a. 数组可以存储基本数据类型的数据,集合不可以。
b. 数组的长度是固定的,集合可以自动调整自己的大小。
c. 数组的效率高,相对来说集合效率比较低。
d. 数组没有API,集合有丰富的API。(丰富的API挺重要)
1. Collection接口
1)概述
a. Collection是层次结构中的根接口。
b. Collection表示一组对象,这些对象也称为 collection 的元素。
c. 一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。
2)API
API:
增:
boolean add(E e) (给collection集合添加指定的元素,可添加重复的元素)
boolean addAll(Collection c) (将指定 collection 中的所有元素都添加到此 collection 中,如果原集合发生了修改,返回true, 否则返回false. )
例:
boolean add(E e):
Collection c = new ArrayList();
c.add("hello");
c.add("world");
c.add("java");
Collection c1 = new ArrayList();
c1.add("beijing");
c1.add("shanghai");
c1.add("shenzhen");
System.out.println(c.addAll(c1)); // true
System.out.println(c); // [hello, world, java, beijing, shanghai, wuhan]
System.out.println(c1); // [beijing, shanghai, wuhan]
Collection c2 = new ArrayList();
System.out.println(c.addAll(c2)); // false
System.out.println(c);//[hello, world, java]
System.out.println(c2);//[]
API:
删:
void clear() (移除此 collection 中的所有元素)
boolean remove(Object o) (从此 collection 中移除指定元素的单个实例,如果存在的话,返回true,不存在,则返回false)
boolean removeAll(Collection c)(移除此 collection 中那些也包含在指定 collection 中的所有元素,如果原集合发生了修改,返回true, 否则返回false)
boolean retainAll(Collection c)(仅保留此 collection 中那些也包含在指定 collection 的元素,如果原集合发生了修改,返回true, 否则返回false.)
例:
boolean removeAll(Collection c):
Collection c = new ArrayList();
c.add("hello");
c.add("world");
c.add("java");
Collection c1 = new ArrayList();
c1.add("beijing");
c1.add("shanghai");
c1.add("shenzhen");
System.out.println(c.removeAll(c1)); // false
System.out.println(c); // [hello, world, java]
System.out.println(c1); //[beijing, shanghai, shenzhen]
boolean retainAll(Collection c):
Collection c = new ArrayList();
c.add("hello");
c.add("world");
c.add("java");
Collection c1 = new ArrayList();
c1.add("beijing");
c1.add("shanghai");
c1.add("shenzhen");
System.out.println(c.retainAll(c1)); // true
System.out.println(c); // []
System.out.println(c1); //[beijing, shanghai, shenzhen]
c1.add("hello");
c1.add("world");
c1.add("java");
System.out.println(c.retainAll(c1)); // false
System.out.println(c); // [hello, world, java]
System.out.println(c1);
API:
查:
boolean contains(Object o) (如果此 collection 包含指定的元素,则返回 true,否则,返回false)
boolean containsAll(Collection c)(如果c中的每一个元素都在集合中存在,就返回true,否则返回false)
API:
获取集合的属性:
boolean isEmpty() (如果此 collection 没有元素,则返回 true)
int size() (返回此 collection 中的元素个数)
API:
遍历:
Object[] toArray() (返回包含此 collection 中所有元素的数组)
Iterator<E> iterator() (返回在此 collection 的元素上进行迭代的迭代器)
例:
Object[] toArray():
Collection c = new ArrayList();
c.add("hello");
c.add("world");
c.add("java");
Object[] array = c.toArray();
for (int i = 0; i < array.length; i++) {
String s = ((String) array[i]);
System.out.println(s.toUpperCase());
}
// 修改数组不会影响到集合。
array[2] = "javase";
System.out.println(Arrays.toString(array)); //[hello, world, javase]
System.out.println(c); //[hello, world, java]
// 修改集合也不会影响到数组.
c.add("javase");
System.out.println(Arrays.toString(array));//[hello, world, java]
System.out.println(c);//[hello, world, java, javase]
例:
Iterator<E> iterator():
Iterator iterator()
迭代器,集合的专用遍历方式
Iterator:
概述:对 collection 进行迭代的迭代器,是一个接口,它依赖于集合对象存在。
API:
boolean hasNext():如果仍有元素可以迭代,则返回 true。
E next(): 返回迭代的下一个元素。
void remove(): 删除的是最近返回的元素
Collection c = new ArrayList();
c.add("hello");
c.add("world");
c.add("java");
Iterator it = c.iterator();
System.out.println(it.next()); // hello
System.out.println(it.next()); // world
System.out.println(it.next()); // java
System.out.println(it.next()); // NoSuchElementException
/*while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s.toUpperCase());
}*/
while (it.hasNext()) {
String s = (String) it.next();
if ("world".equals(s)) {
it.remove();
}
}
System.out.println(c);//[hello, java]
使用迭代器时的注意事项:
a. 用迭代器对集合遍历的时候,不要使用集合的API对集合进行修改,因为会发生ConcurrentModificationException
b. 不建议使用while循环, 可以使用for循环, 最好使用foreach循环.
Collection c = new ArrayList();
c.add("hello");
c.add("world");
c.add("java");
Iterator it = c.iterator();
// 在遍历的过程中使用集合的API对集合进行删除"hello"操作
//ConcurrentModificationException,操作失败
while (it.hasNext()) {
Object obj = it.next(); // ConcurrentModificationException
if ("hello".equals(obj)) {
c.remove(obj);
}
}
// 在遍历的过程中使用迭代器进行删除"hello"操作,成功
Collection c = new ArrayList();
c.add("hello");
c.add("world");
c.add("java");
for(Iterator it = c.iterator(); it.hasNext(); ) {
Object obj = it.next();
if ("hello".equals(obj)) {
it.remove();
}
}
3)关于迭代器的画图说明
2. List接口
1)概述
List extends Collection:
概述:
它是有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。
用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
与 set 不同,列表通常允许重复的元素。更确切地讲,
列表通常允许满足 e1.equals(e2) 的元素对 e1 和 e2,
并且如果列表本身允许 null 元素的话,通常它们允许多个 null 元素。
2)特有的API
增:
void add(int index, E element) (在列表的指定位置插入指定元素)
(Index范围:[0, size()])
boolean addAll(int index, Collection c) (添加指定 collection 中的所有元素到此列表的结尾,
顺序是指定 collection 的迭代器返回这些元素的顺序,
如果原List集合发生了修改,返回true, 否则返回false.)
(Index范围:[0, size()])
查:
E get(int index)
返回列表中指定位置的元素(Index范围: [0, size()-1])
int indexOf(Object o)
获取集合中第一个与指定对象o相等元素的索引,如果集合中没有和o相等的元素, 返回-1.
int lastIndexOf(Object o)
获取集合中最后一个与指定对象o相等元素的索引,如果集合中没有和o相等的元素, 返回-1.
删:
E remove(int index)
删除指定索引位置的元素, 并把被删除的元素返回(Index范围:[0, size()-1])
改:
E set(int index, E element)
用element替换指定索引位置的元素,并把该位置原来的元素返回(Index范围:[0, size()-1])
遍历:
ListIterator<E> listIterator()
返回此列表元素的列表迭代器。
ListIterator<E> listIterator(int index)
返回列表中元素的列表迭代器,从列表的指定位置开始。
遍历:
ListIterator<E> listIterator()
迭代器位于最前面
ListIterator<E> listIterator(int index) 范围:[0, size()]
可以指定迭代器的位置,下一个元素的索引位置为index
ListIterator extends Iterator
概述:系列表迭代器,允许程序员按任一方向遍历列表、迭代期间修改列表
(但不可以用集合api修改,ConcurrentModificationException),
并获得迭代器在列表中的当前位置
API:
boolean hasNext()
boolean hasPrevious()
E next()
E previous()
int previousIndex(): 迭代器前一个元素的索引
int nextIndex():迭代器后一个元素的索引
void add(E e)
void remove():删除最近返回的元素
void set(E e):被替换的是最近返回的元素
例:
List list = new ArrayList();
list.add("赵灵儿");
list.add("王语嫣");
list.add("小龙女");
// 练习2:在王语嫣前面添加茜茜
for(ListIterator it = list.listIterator(list.size()); it.hasPrevious(); ) {
String s = (String) it.previous();
if ("王语嫣".equals(s)) {
it.add("茜茜");
}
}
System.out.println(list);//[赵灵儿,茜茜,王语嫣,小龙女]
// 练习3:在王语嫣前面添加茜茜(用集合的API添加)
for(ListIterator it = list.listIterator(list.size()); it.hasPrevious(); ) {
String s = (String) it.previous();
if ("王语嫣".equals(s)) {
int index = it.nextIndex();
list.add(index, "茜茜");//ConcurrentModificationException
}
}
System.out.println(list);
// 练习2:删除王语嫣
for(ListIterator it = list.listIterator(); it.hasNext(); ) {
String s = (String) it.next();
if ("王语嫣".equals(s)) {
it.remove();
}
}
System.out.println(list);//[赵灵儿,小龙女]
//练习2:把王语嫣替换成茜茜
for(ListIterator it = list.listIterator(); it.hasNext(); ) {
String s = (String) it.next();
if ("王语嫣".equals(s)) {
it.set("茜茜");
}
}
System.out.println(list);//[赵灵儿,茜茜,小龙女]
// 练习3:把王语嫣替换成茜茜(用集合的API)
for(ListIterator it = list.listIterator(); it.hasNext(); ) {
String s = (String) it.next();
if ("王语嫣".equals(s)) {
int index = it.previousIndex();
list.set(index, "茜茜");//例外,没有运行异常,可以正确执行
}
}
System.out.println(list);//[赵灵儿, 茜茜, 小龙女]
截取:
List<E> subList(int fromIndex, int toIndex) Index值包左不包右
返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。
例:
List list = new ArrayList();
list.add("赵灵儿");
list.add("王语嫣");
list.add("小龙女");
List subList = list.subList(1, 2);
System.out.println(subList); //[王语嫣]
System.out.println(subList.size()); //1
subList.remove(0);
System.out.println(subList);// []
System.out.println(list); //[赵灵儿, 小龙女]
//原List集合的"王语嫣"元素被删除
//原因:sublist方法返回的新List集合,和调用该方法的List集合共享被截取的元素(视图技术),
//新List集合删除了"王语嫣",那么原List集合中的"王语嫣"元素自然也不存在了