JavaSE|集合类、Collection、Iterator
集合类概述
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,Java就提供了集合类。
数组和集合的区别
- 长度区别:数组长度固定;集合长度可变。
- 内容不同:数组存储的是同一种类型的元素;而集合可以存储不同类型的元素。
- 元素的数据类型:数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用类型。
集合类的特点
- 集合只用于存储对象;
- 集合长度是可变的;
- 集合可以存储不同类型的对象。
集合的继承体系
由于需求不同,Java提供了不同的集合类。虽然这多个集合类的数据结构不同,但它们都要提供存储和遍历功能。我们把它们的共性不断向上提取,最终形成了集合的继承体系结构。
- Collection
- | – List
- | – ArrayList
- | – Vector
- | – LinkedList
- | – Set
- | – HashSet
- | – TreeSet
- | – List
Collection
Collection 层次结构中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。
功能概述
-
添加功能
boolean add(Object obj):添加一个元素
boolean addAll(Collection c):添加一个集合的元素 -
删除功能
void clear():移除所有元素
boolean remove(Object obj):移除一个元素
boolean removeAll(Collection c):移除一个集合的元素 -
判断功能
boolean contains(Object obj)
判断集合中是否包含指定的元素
boolean containsALL(Collection c))
判断集合中是否包含指定的集合元素,包含指定集合所有元素才返回true
boolean isEmpty():判断集合是否为空 -
获取功能
Iterator iterator():见下一个标题处。 -
长度功能
int size():元素的个数
面试题:数组有没有length()方法?字符串有没有length()方法?集合有没有length()方法?(没有;有;没有) -
交集功能
boolean retainAll(Collection c)
两个集合都有的元素。返回值为true代表原集合元素发生改变,否则返回false。 -
把集合转换为数组
Object[] toArray()
Collection集合的遍历
- 把集合转数组Object[] toArray(),然后进行遍历。
- 迭代器(集合专用方式)
集合的操作步骤
- 创建集合对象
- 创建元素对象
- 把元素添加到集合
- 遍历集合
Iterator
public interface Iterator
迭代器是集合获取元素的方式。迭代器是依赖于集合存在的。
Collection的成员方法:Iterator iterator()
成员方法
1. Object next():获取元素,并移动到下一个位置。
可能抛出的异常:NoSuchElementException,代表没有下一个元素,已经找到最后了。所以可以在每次获取时,先判断是否有下一个元素。
// 创建集合对象
Collection c = new ArrayList();
c.add("hello");
c.add("world");
c.add("java");
// Iterator iterator():迭代器,集合的专用遍历方式
Iterator it = c.iterator(); // 实际返回的肯定是子类对象,这里是多态
while (it.hasNext()) {
// System.out.println(it.next());
String s = (String) it.next();
System.out.println(s);
}
2. boolean hasNext()
如果仍有元素可以迭代,则返回 true。(换句话说,如果 next 返回了元素而不是抛出异常,则返回 true)。
需要注意的问题
- 可以用for循环替换while循环,且由于块运行完后迭代器对象变成垃圾,for的效率比while更高。
Collection c = new ArrayList();
Student s1 = new Student("Sally", 20);
Student s2 = new Student("Jenny", 23);
Student s3 = new Student("Yu", 21);
c.add(s1);
c.add(s2);
c.add(s3);
/*Iterator iter = c.iterator();
while(iter.hasNext()){
Student s = (Student) iter.next();
System.out.println(s);
}*/
for(Iterator it = c.iterator(); it.hasNext();){
Student s = (Student) it.next();
System.out.println(s);
}
- 不要多次使用 next() 方法,因为每次使用都会移动到下一个位置。所以推荐先通过 next() 方法获取对象,然后再进行操作。
Collection c = new ArrayList();
// 创建学生对象
Student s1 = new Student("林青霞", 27);
Student s2 = new Student("风清扬", 30);
Student s3 = new Student("令狐冲", 33);
Student s4 = new Student("武鑫", 25);
Student s5 = new Student("刘晓曲", 22);
// 把学生添加到集合中
c.add(s1);
c.add(s2);
c.add(s3);
c.add(s4);
c.add(s5);
// 遍历
Iterator it = c.iterator();
while (it.hasNext()) {
Student s = (Student) it.next();
System.out.println(s.getName() + "---" + s.getAge());
// NoSuchElementException 不要多次使用it.next()方法
// System.out.println(((Student) it.next()).getName() + "---"
// + ((Student) it.next()).getAge());
}
原理理解
- 迭代器为什么不定义成一个类,而是接口?
A:假设迭代器定义的是一个类,这样我们就可以创建该类对象,调用该类方法来实现集合的遍历。但是,Java中提供了很多集合类,而这些集合类的数据结构不同,故其存储和遍历的方式应该不同。所以没有定义迭代器类。
无论是哪种集合,都应该具备获取元素的操作,并且最好辅助与判断功能,先判断再获取,不容易出错。即判断功能和获取功能应该是一个集合遍历所具备的,而每种集合的方式又不尽相同,故将这两个功能提取出来,并不提供具体实现,这种方式就是接口。
真正的具体实现类,在具体子类中,以内部类的方式体现。
Iterator源码如下:
public interface Inteator {
boolean hasNext();
Object next();
}
public interface Iterable {
Iterator iterator();
}
public interface Collection extends Iterable {
Iterator iterator();
}
public interface List extends Collection {
Iterator iterator();
}
// 具体的子类中以内部类的方式实现了iterator()方法。
public class ArrayList implements List {
public Iterator iterator() {
return new Itr();
}
private class Itr implements Iterator {
public boolean hasNext() {}
public Object next(){}
}
}
Collection c = new ArrayList();
c.add("hello");
c.add("world");
c.add("java");
Iterator it = c.iterator(); //new Itr();
while(it.hasNext()) {
String s = (String)it.next();
System.out.println(s);
}
案例
- 存储字符串并遍历
- 存储自定义对象并遍历