持有对象(集合)
1、基本概念
-
java容器类类库的用途是“保存对象”,并将其划分为两个不同的概念:
Collection:一个独立元素的序列,这些元素服从一条或多条规则。List必须按照插入顺序保存元素,而Set不能有重复元素。Queue按照排队规则来确定对象产生的顺序(通常与被插入的顺序相同)。
Map:一组成对的“键值对”对象,允许你使用键查找值。
Collection接口概括了序列的概念——一种存放一组对象的方式。所有的Collection都可以用foreach语法遍历。
2、添加一组元素
java.util包中Arrays和Collections类中都有很多实用方法。Arrays.asList()方法接受一个数组或是一个用逗号分隔的元素列表(使用可变参数),并将其转换为一个List对象。Collections.addAll()方法接受一个Collection对象,以及一个数组或是一个用逗号分隔的列表,将元素添加到Collection中。
Collection.addAll()成员方法只能接受另一个Collection对象作为参数,因此它不如Arrays.asList()或Collections.addAll()灵活,这两个方法使用的都是可变参数列表。
直接使用Arrays.asList()的输出当作List,在这种情况下,其底层表示的是数组,因此不能调整大小。如果你试图用add()或delete()方法在这种列表中添加或删除元素,运行时会报错。
Arrays.asList()中间可以插入一条“线索(参数类型)”,以告诉编译器对于有Arrays.asList()产生的List类型,这称为显式类型参数说明。
3、容器的打印
java容器类库中有两种主要类型,区别在于容器中每个“槽”保存的元素个数。Collection在每个槽中只能保存一个元素,此类容器包括:List,它以特定的顺序(插入顺序)保存一组元素;Set,元素不能重复;Queue,允许在容器的一端插入元素,并从另一端移除元素。Map在每个槽内保存了两个对象,即键和与之相关联的值。
Collection打印出来的内容用方括号括住,每个元素用逗号分隔。Map则用大括号括住,键与值由等号联系。
ArrayList和LinkedList都是List类型。
HashSet、TreeSet和LinkedHashSet都是Set类型,每个相同的项只保存一次,不同的Set实现存储元素的方式不同。HashSet使用的是相当复杂的方式来存储,是最快的获取元素方式,存储顺序貌似并无实际意义。存储顺序重要,可以使用TreeSet,它按照比较结果的升序保存对象;或者使用LinkedHashSet,它按照被添加顺序保存对象。
HashMap、TreeMap和LinkedHashMap都是Map类型,对于每个键,Map只接受存储一个值。与HashSet一样,HashMap也提供了最快查找技术,也没按照任何明显的顺序来保存元素。TreeMap按照比较结果的升序保存键,而LinkedHashMap则按照插入顺序保存键,同时还保留了HashMap的查询速度。
4、List
List接口在Collection的基础上添加了大量的方法,使得可以在List中间插入或移除元素。
-
两种类型的List:
基本的ArrayList,它长于随机访问元素,但在List中间插入和移除元素时较慢。
LinkedList,它用较低代价完成在List中间进行插入和删除操作,提供了优化的顺序访问。LinkedList在随机访问方面相对较慢,但它的特性集较ArrayList更大。
-
常用方法:
contains(Object obj):用来确定某个对象是否在列表中。
remove(Object obj):移除一个对象。
indexOf(Object obj):返回该对象在List中所处位置的索引编号。
subList(int beginIndex,int endIndex):从较大列表中创建出一个子列表。注:对所返回的子列表的修改会反映到初始列表中,反之亦然。
containsAll(List<Object> list):用来确定子列表是否在较大列表中。如果在,即使使用Collections.sort(List<?> list)或Collection.shuffle(List<?> list)改变子列表中元素的顺序,不会影响其结果。
retainAll(List<?> list):有效的交集操作,保留两个List中同时存在的元素。
removeAll(List<?> list):将从某个List中移除参数List中的所有元素。
set(int index,Object obj):在指定的索引处(第一个参数),用第二个参数替换这个位置的元素。
addAll(List<?> list):重载的Collection接口中的方法,可以从中间插入(Collection中的addAll()方法是追加到列表尾)。
clear():移除列表中的所有元素。
isEmpty():判断列表是否为空。
toArray():将任意的Collection转换为一个数组。
5、迭代器
-
java的Iterator只能单向移动,这个Iterator只能用来:
使用方法iterator()要求容器返回一个Iterator。Iterator将准备好返回序列的第一个元素。
使用next()获得序列中的下一个元素。
使用hasNext()检查序列中是否还有元素。
使用remove()将迭代器新近返回的元素删除。
只是向前遍历List,并不打算修改List对象本身,foreach语法显得更加简洁。
Iterator移除由next()产生的最后一个元素,意味着在调用remove()之前必须先调用next()。
迭代器统一了对容器的访问方式。
ListIterator是一个更加强大的Iterator的子类型,只能用于各种List类的访问。通过调用listIterator()方法产生一个指向List开始处的ListIterator,并且还可以通过调用listIterator(int n)方法创建一个一开始指向列表索引为n的元素处的ListIterator。
-
ListIterator和Iterator的区别:
ListIterator有add()方法,可以向List中添加对象,而Iterator不能
ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iterator仅能遍历,不能修改。
6、LinkedList
-
LinkedList添加了可以使其用作栈(Stack)、队列(Queue)或双端队列的方法:
getFirst()和element()完全一样,都返回列表头(第一个元素),而并不移除它,如果List为空,则抛出NoSuchElementException异常。peek()方法与这两方法稍有差异,列表为空时返回null。
removeFirst()和remove()也是完全一样的,它们移除并返回列表的头,而在列表为空时抛出NoSuchElementException。poll()稍有差异,它在列表为空时返回null。
addFirst()在列表的开始位置插入一个元素。
offer()、add()、addLast() 相同,它们都将某个元素插入到列表的尾端。
removeLast()移除并返回列表的最后一个元素。
-
在LinkedList的基础上添加offer()、element()、peek() 、poll()和remove()方法,使其成为一个Queue实现。
7、Stack
栈通常是指“后进先出”的容器。
LinkedList具有能够直接实现栈的所有功能方法,因此可以直接将LinkedList作为栈使用。
注:peek()方法将提供栈顶元素,但是并不将其从栈顶移除,而pop()将移除并返回栈顶元素。
8、Set
Set不保存重复的元素。Set具有与Collection完全一样的接口,没有添加任何额外的功能,实际上Set就是Collection,只是行为不同。
Set的实现具有不同的元素存储方式。TreeSet将元素存储在红-黑树的数据结构中,而HashSet使用的是散列函数。LinkedHashSet因为查询速度的原因也使用了散列,但看来它使用了链表来维护元素的插入顺序。
9、Map
containsKey()和containsValue(),查看Map是否包含某个键或某个值。
keySet()方法返回Map中所有键组成的Set。
10、Queue
队列是一个典型的先进先出(FIFO)的容器。LinkedList提供了方法以支持队列的行为,并且它实现了Queue接口,因此LinkedList可以看作Queue的一种实现。
与Queue相关的方法提供了完整而独立的功能,即,对于Queue所继承的Collection,再不需要使用它任何方法的情况下,就可以拥有一个可用的Queue。
PriorityQueue(优先级队列),声明下一个弹出的元素是最需要的元素(具有最高优先级)。在PriorityQueue上调用offer()方法来插入一个对象时,这个对象会在队列中被排序,默认的排序将使用对象在队列中的自然顺序,也可以通过自己提供Comparator来修改这个顺序。
Collection.reverseOrder()产生反序的Comparator。
11、Collection和Iterator
Collection接口和Iterator都可以与底层特定容器实现解耦。当一个类是实现了Collection的类时,可以使用foreach结构,从而使代码更清晰。但是实现一个不是Collection的外部类时,让它去实现Collection接口麻烦,使用Iterator更方便。
12、foreach与迭代器
foreach语法主要用于数组,但也可以应用于任何Collection对象(你创建的任何实现Iterable的类,都可以将它用于foreach语句中)。
Arrays.asList()产生的List对象会使用底层数组作为其物理实现。只要你执行的操作会修改这个List,并且你不想原来的数组被修改,那么就应该在另一个容器中创建一个副本。
13、总结
-
Vector:
用ArrayList代替Vector。Vector是线程安全的,而有的时候我们确实希望在多线程的情况下使用列表,那么这个时候我们可以利用Collections这个类当中为我们提供的synchronizedList(List list),它可以返回一个线程安全的同步的列表,还提供了返回同步的Collections。Hashtable:
用HashMap代替Hashtable。Hashtable是线程安全的,而有的时候我们确实希望在多线程的情况下使用HashMap,那么这个时候我们可以利用Collections这个类当中为我们提供的synchronizedMap(Map<K,V> m),它可以返回一个线程安全的同步的HashMapStack:
用LinkedList代替Stack。当初在设计Stack的时候就有一些潜在的问题,它是从Vector继承而来,对于一个栈来说,它只能是最后放进去的元素,要先出来,但是它继承自Vector,而Vector中有一个方法叫做elementAt(int index),而不能说是通过这个索引index去任意的获得一个元素。结果它就有了这个奇怪的特性,提倡应该自己利用LinkedList去实现一个stack。
其实只有四种容器:Map、List、Set和Queue,它们各有两到三个实现版本。常用的容器用黑色粗线框表示。点线框表示接口,实线框表示普通类。带有空心箭头的点线表示一个特定的类实现了一个接口,实心箭头表示某个类可以生成箭头所指向类的对象。
转载于:https://my.oschina.net/90liusq/blog/314645