22.JAVA核心技术—集合
集合框架图:
((Iterator接口 <----)) Iterable接口 ← Collection接口
↑
┌--------------------------------┬---------------┐
Set接口 List接口 Queue接口 Map接口
↑ ↑ ↑ ↑
┌----------┐ ┌-----------+---------┐ ┌-----------┐ ┌----------┐
HashSet SortedSet接口 Vector ArrayList LinkedList PriorityQueue HashMap SortedMap接口
↑ ↑
TreeSet TreeMap
1.集合接口
1)Iterable接口只有一个方法,public Iterator iterator(),返回类型是Iterator,它与Iterator接口没有关系。
2)迭代器:(Iterator)遍历元素,所有实现了Iterable接口的集合都可以使用迭代器遍历元素。
Iterator接口的三个方法使用说明:hasNext():是否还有一个元素
next():指向下一个元素,并返回跨过的元素
remove():将最近一次next返回的元素删除(安全的从Collection底层中删除)
3)Collection接口是集合接口的父接口(除了Map接口)。与Collections的区别在于Collections是个工具类,而Collection是个接口。
4)List、Set、Queue、Map接口:List接口是有序的、元素可重复;Set接口是无序的、元素不可重复;Map接口每个元素是个键值对,键不可重复,值可以,可
以有空键;Queue接口,队列,先进先出。
5)SortedSet接口和SortedMap接口是排序接口。
注:集合类库中提供了一个Iterator的子接口ListIterator。这个子接口的功能如下:
List接口有两个返回ListIterator接口的方法。listIterator()、listIterator(int index)
ListIterator接口: add(E newElement)将一个元素添加到当前位置的前面。
set(E newElement)以指定的元素取代next或previous方法访问的那个元素;
hasPrevious()和previous()跟Iterator接口中的hasNext()和next()方法功能相似。
2.具体的集合(集合接口的实现类)
1)List接口的实现类:ArrayList类、LinkedList类、Vector类
ArrayList底层是数组,查询速度快,增删慢;Vector底层是数组,但他是个线程安全的;
LinkList是个链表,查询效率低,增删高。链表上每个数据节点是由前继指针,数据,后继指针组成。
2)Set接口的实现类和子接口及其实现类:HashSet类、SortedSet接口、TreeSet接口
HashSet(散列集)集合是无序的,元素不可重复。底层也是一个数组(链表的数组)。
如何保证元素不重复?Hash算法和equals方法。当添加元素的时候,先计算对象的hashCode(哈希吗),
int hc=obj.hashCode(),int i=hc%n;(你为数组的长度),利用余数在数组相应的位置添加。如果
位置有元素了先比较哈希吗,如返回true,再调用equals比较如返回true,元素相等,不用添加。
若返回false就去找其他位置添加。
注意:我们用我们自己定义的类来使用HashSet添加对象时,这个类一定要实现hashCode和equals方法。
TreeSet(树集)是SortedSet的实现类,是个排序集合,默认的是字典排序,元素要实现Comparable接口。
注意:将一个元素添加到树集的速度比将它添加到散列集的速度慢,但比添加到数组和链表的速度要快。
集合的排序:a. Collections.sort(List list)对指定的List进行排序。如果list里的元素是个自定义对象,就不能用这个方法
了,就必须使用下面的方法。
b.实现Comparable接口,即实现这个接口的compareTo(Object obj)方法,比较当前对象与指定对象的顺
序。当前对象>obj 返回>0;当前对象<obj 返回<0 ;当前对象=obj 返回=0
c.将一个Comparator对象传递给树集的构造参数,Comparator接口有个方法compare(Object,Object)。
注意:使用Comparable接口定义的排序具有局限性,对于给定的类该接口只能实现一次,如果在一个集合中需要按照编号进行排序,在另一个集合中需要按照
信息排序该怎么么办?这个时候需要使用Comparator接口,如上c.
3)Queue接口的实现类:LinkedList类、PriorityQueue类
优先级队列:它是一种能够在以任意顺序插入元素后,再按排序顺序读取这些元素的数据结构。
注意:优先级队列并不是对所有的元素进行排序,比如我们对各个元素进行迭代,各个元素不需要排序,但是调用add和
remove方法的时候总会将最小的元素移动的根。
优先级队列所有的元素可以实现Comparable接口的类的对象,也可是在构造器中提供实现Comparator接口的对象
4)Map接口的实现类和子接口及其实现类:HashMap类、SortedMap接口、TreeMap类。
映射表:用于存放键值对,键是唯一的。 映射表的两个通用实现:HashMap(散列映射表)、TreeMap(树状映射表)。
HashMap对键进行散列,TreeMap则使用键的全局顺序进行排序,并将其组织成树。
HashMap的运行速度比TreeMap的运行速度快。
方法:Set<k> keySet()//得到所有的键
Collection<K> values()//得到所有的值
Set<Map.Entry<K,V>> entrySet()//得到键和值
for(Map.Entry<String ,Employee> entry:hashset.entrySet()){
String key=entry.getKey();
Employee value=entry.getValue();
...........
}
3.视图和包装器
1)视图:通过使用视图,我们可以获得其他实现了Collection或Map接口的对象。如映射表中的keySet方法就是一个很好的列
子,keySet方法返回的是一个实现了Set接口的类的对象(集合),同时该类的各个方法将对源映射表进行操作,这种
集合被 称为视图。视图只是包装了接口不是实际的集合对象。
2)轻量级集合包装器
a. Arrays类有个静态的方法asList(),它返回包装了一个普通的Java数组的List包装器。如:
Card[] card=new Card[52];.........
List<Card> cardList=Arrays.asList(card);//返回的不是一个ArrayList对象,只是一个视图。
List<Card> cardlist=Arrays.asList("Amy","Bob","Cari");
b. Collections工具类的静态方法nCopies()
Collections.nCopies(n,anObject)//返回一个实现List接口的不可修改的对象,并会产生一种包含n个元素,每个元素看
上去都像是一个anObject的错觉。
Collections.singleton(anObject)//返回一个实现了Set接口的视图对象。
3)子范围视图
List group=staff.subList(10,20//从staff列表中获取第10至19个元素。
4)不可修改视图
Collections类拥有一些方法,用于构建集合的不可修改视图。这些视图对现有集合增加了一次运行期检查,如果发现谁视
图对该集合进行修改,就会抛出异常,同时该集合将保持未修改的状态。
List<String> staff=new LinkedList<String>();
Collections.unmodifiableList(staff);//返回一个实现了List接口的某个类的对象。
注意:不可修改视图并不是使集合本身不可修改。我们任然可以通过集合的原始引用来修改集合。
5)同步视图
Java类库的设计者没有实现线程—安全集合类,而是使用视图机制来保证常规的集合线程安全。
如Collections.synchronizedMap方法可以将任何一个映射表转换成一个具有同步访问方法的Map,
HashMap<String,Employee> hasMap=new HshMap<String,Employee>();
Map<String,Employee>map=Collections.sychronizedMap(hasMap);
注意:视图只是对集合的方法进行了序列化,如果想使用迭代器的话,就需要手工获取集合对象上的锁,如
synchronized(map){
Iterator<String> iter=mapkeySet();....
}
6)被检验视图
ArrayList<String> strings=new ArrayList<String>();
ArrayList rawList=strings;
rawList.add(new Date());
上述代码中错误的add方法在运行时并不能被检测到,只有在稍后代码的另一部分调用get方法并将结果转化为String时,才
抛出异常。此时被检验师徒可以探测到这类问题。定义:
List<String> safeString=Collections.checked:List(strings,String.class);
4 批操作、数组和集合的转换
批操作,如希望查找两个集合的交集,
Set<String> result=new HashSet<String>(a);
result.retainAll(b)//该方法保留所有在a中也在集合b中的元素。
数组转为集合: String[] values=......;
HashSet<String> staff=new HashSet<String>(Arrays.asList(values));
集合转为数组:String[] values=staff.toArray(new String[0]);
String[] values=(String[])staff.toArray();//Error,返回的是一个Object[]数组,我们无法改变类型。