Java平台提供了一个全新的集合框架。“集合框架”主要由一组用来操作对象的接口组成。不同接口描述一组不同数据类型。
在面向对象思想里,一种数据结构也被认为是一个容器。
Java集合框架支持以下两种类型的容器
1、为了粗存一个元素的集合,简称为集合(collection)
2、是为了存储键/值对,称为图(Map)
一、迭代器
迭代器是一个对象,它的工作是遍历并悬着序列中的对象,而客户端程序员不需要知道该序列底层的结构。统一了对容器的访问方式
public class IteratorTest {
public static void main(String[] args){
List<String> list = new ArrayList<String>(Arrays.asList(("a b c d e f g h i").split(" ")));
Iterator<String> iterator = list.iterator();//要求容器返回一个Iterator
while (iterator.hasNext()) {//检查序列中是否还有元素
System.out.print(iterator.next() + " ");
}
iterator = list.iterator();
for (int i = 0; i < 4; i++) {
iterator.next();//获得序列的下一个元素
iterator.remove();//将迭代器新近返回的元素删除
}
System.out.println(list);
}
}
Iterator还可以移除由next()产生的最后一个元素,这意味着在调用remove()之前必须调用next()
ListIterator接口扩展了Iterator接口,以增加对线性表的双向遍历能力。
可选操作
collection中的有些方法是不能再具体子类中实现的,在这种情况下,抛出异常java.lang.UnsupportedOperationException.可以防止出现接口爆炸的情况
public class Test{
static void test(String msg, List<String> list){
System.out.println("-----" + msg + "-----");
Collection<String> c = list;
System.out.println(c);
try {
c.clear();
} catch (Exception e) {
System.out.println("clear :" + e);
}
}
public static void main(String[] args){
List<String> list = Arrays.asList(("A B C D E F G H I J K L").split(" "));
test("modifiable", new ArrayList<String>(list));
test("unmodifiableList", list);
}
}
输出
-----modifiable-----
[A, B, C, D, E, F, G, H, I, J, K, L]
-----unmodifiableList-----
[A, B, C, D, E, F, G, H, I, J, K, L]
clear :java.lang.UnsupportedOperationException
因为Arrays.asList()会生成一个List,它基于一个固定大小的数组,仅支持哪些不会改变数组大小的操作
应该将Arrays.asList()的结果作为构造器的参数传递给任何Collection,这样就生成允许使用所有的方法的普通容器
比较器接口Comparator
Comparable是在集合内部定义的方法实现的排序,位于java.lang下。
Comparator是在集合外部实现的排序,位于java.util下。Comparable是一个对象本身就已经支持自比较所需要实现的接口,如String、Integer自己就实现了Comparable接口,可完成比较大小操作。自定义类要在加入list容器中后能够排序,也可以实现Comparable接口,在用Collections类的sort方法排序时若不指定Comparator,那就以自然顺序排序。所谓自然顺序就是实现Comparable接口设定的排序方式。
Comparator是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足要求时,可写一个比较器来完成两个对象之间大小的比较。
Comparator体现了一种策略模式(strategy design pattern),就是不改变对象自身,而用一个策略对象(strategy object)来改变它的行为。
Comparable:
public class Animal implements Comparable<Animal>{
private int age;
public Animal(int age) {
this.age = age;
}
public int getAge() {
return age;
}
@Override
public int compareTo(Animal o) {
// 实现Comparable接口要覆盖compareTo方法
return this.age - o.getAge();
}
}
Comparator:
public class AnimalComparator implements Comparator<Animal>{
@Override
public int compare(Animal o1, Animal o2) {
if(o1.getAge() > o2.getAge())
return -1;
else if (o1.getAge() == o2.getAge())
return 0;
else
return 1;
}
public static void fillSet(Set<Animal> set){
set.add(new Animal(1));
set.add(new Animal(2));
set.add(new Animal(3));
set.add(new Animal(4));
set.add(new Animal(5));
}
public static void printSet(Set<Animal> set){
for (Animal animal : set) {
System.out.print(animal.getAge() + " ");
}
System.out.println();
}
public static void main(String[] args){
Set<Animal> set = new TreeSet<Animal>();
Set<Animal> set1 = new TreeSet<Animal>(new AnimalComparator());
fillSet(set);
fillSet(set1);
printSet(set);
printSet(set1);
}
}
输出
1 2 3 4 5
5 4 3 2 1
若使用一个未实现Comparable接口的类
class Animal{
private int age;
public Animal(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
//....
public static void main(String[] args){
Set<Animal> set1 = new TreeSet<Animal>(new AnimalComparator());
fillSet(set1);
printSet(set1);
Set<Animal> set = new TreeSet<Animal>();
fillSet(set);
printSet(set);
}
结果
5 4 3 2 1
Exception in thread "main" java.lang.ClassCastException: com.example.collection.Animal cannot be cast to java.lang.Comparable
at java.util.TreeMap.compare(Unknown Source)
因为TreeSet并不知道该如何put
解决办法:
1、在构造TreeSet时指定一个比较器Comparator,这个比较器用于比较两个值,并且返回一个整数值作为他们的比较结果。
2、要实现Comparable接口。
二、集合
支持三种主要类型的集合:规则集(set), 线性表(List)和队列(Queue).这些集合的通用特性都被定义在接口中,它的实现是在具体类中提供的。
AbstractCollection类提供了Collection接口部分实现。
1、规则集(Set)
规定Set的实例不包含重复的元素
AbstracSet类提供equals和hashCode方法的具体实现
HashSet
可以储存互不相同的任何元素,添加到散列集中的对象必须以一种正确分散散列码的方式来实现hashCode()方法。散列集中的元素是没有特定顺序的。
LinkedHashSet
是一个用链表实现来扩展HashSet类,支持对规则集内的元素排序,保持元素插入时的顺序。元素必须定义hashCode()方法
TreeSet
确保规则集中的元素是有序的,只要对象是可以相互比较的,就可以将它们添加到一个树形集中
使用Comparable接口中的CompareTo方法对树形集排序
2、线性表(List)
允许在一个集合中存储重复的元素,而且用户可以指定他们的存储位置,通过下标来访问元素。
1、ArrayList,由数组支持,在中间插入和移除元素时较慢
2、LinkedList,由链表实现,它通过代价较低的插入和删除操作,提供了优化的顺序访问,在随机访问方面比较慢。
规则表比线性表更加高效,如果应用程序用规则集就足够,就使用规则集。
3、队列(Queue)
队列是一种先进先出的数据结构,元素被追加在队列末尾,然后从队列头删除。在优先队列中,拥有最高优先级的元素首先被删除。
可以使用LInkedList创建一个队列
4、图
依照键值存储元素的容器。
HashMap
不会根据插入的顺序将键值对进行排序,并且存储顺序是随机的。
LinkedHashMap
用链表实现来扩展HashMap,支持图中条目的排序。
1、按照插入图的顺序排序
2、按最后一次访问的顺序,从最早到最晚(访问顺序)
TreeMap
在遍历排好顺序的键值时是很高效的,键值使用Comparable或Comparator来排序。