原创

【每天十分钟JAVA快速入门】(十五)集合类

集合类

上一节我们学习了Java中定义的一些主要的集合接口,下面列出了一些常用的集合类以及它们的特征,当然这不是全部的集合类。
集合类
特征
ArrayList
可以动态增长和缩减的索引序列
LinkedList
可以在任何位置进行高效地插入和删除操作的有序序列
HashSet
没有重复元素的无序集合
TreeSet
没有重复元素的有序集合
ArrayDeque
用循环数组实现的双端队列
PriorityQueue
允许高效删除最小元素的集合
HashMap
存储键值对数据结构
TreeMap
键值有序排列的映射表

ArrayList
之前在学习数组的时候我们已经知道,数组一旦确定了大小就不可改变了,如果需要动态增长和缩减,最简单的办法就是使用ArrayList类。ArrayLit是一个泛型类,下面我们来获得一个存储String元素的ArrayList:
ArrayList<String> strings = new ArrayList<>();
ArrayList底层实现还是是基于数组的,只不过在它引用的内部数组空间耗尽时可以自动地创建一个更大的数组将原来的元素全部拷贝过来。
使用add方法在ArrayList尾部添加元素,可以保证元素按照添加的顺序存储,因此ArrayList是一个有序集合。
可以使用迭代器来顺序访问元素。
也可以使用get(int i)方法来随机访问第i个元素,例如:
strings.get(0);
使用set(int i,E element)设置第i个元素,例如:
strings.set(0,"0");
使用get,set方法时,i一定要小于ArrayList的长度,否则会抛出java.lang.IndexOutOfBoundsException异常,由于strings没有初始化,实际上长度为0,因此上面的get,set都是错误的。
使用size()方法来获取ArrayList的长度。

LinkedList
由于ArrayList是基于数组的,因此它有一个很大的缺陷就是在中间位置删除或添加一个元素代价很大。LinkedList就可以解决这个问题,Java中的LinkedList是基于双向链表的。LinkedList.add方法将元素添加在尾部,但是使用LinkedList常常是因为要在元素添加到中间,我们之前已经了解到Iterator描述了集合中的位置,因此这种基于位置的add可以由Iterator来处理,Iterator的子接口ListIterator就定义了add方法,例如,在LinkList的第1个和第2个元素中间插入一个新的元素:
List<String> strings = new LinkedList<>();
strings.add("0");
strings.add("1");
strings.add("2");
ListIterator<String> lit = string.listIterator();
lit.next(); //迭代器移动到第一个元素后面,形如:0|12
lit.add("X"); // 在迭代器位置之前添加一个元素X,0X|12
尽管链表不支持快速地随机访问,LinkedList还是提供了一个get(int index)方法,显然这个方法的效率不会高,我们应该尽量避免使用这样的方法。
使用LinkedList的目的就是减少在列表中插入或删除元素的代价,如果我们可以预测到列表中的元素不多,那完全可以使用ArrayList。

HashSet
Java提供了一个HashSet类,它实现了基于散列表的集,可以在不关心集合中元素的顺序时使用HashSet。HashSet中的元素不允许重复。

TreeSet
TreeSet与HashSet类似,不过它是一个有序集合,使用树结构完成排序,当前的实现是红黑树。使用TreeSet则所有的元素都必须能够比较,即实现Comparable接口,可以以任意顺序插入集合,遍历时自动根据排序结果展现。

ArrayDeque
ArrayDeque是基于循环数组实现的双端队列,可以增加队列长度。双端队列就是有两个端头的队列,Queue提供的API很多都是成对出现的,区别在于出现非法操作时一个抛异常,另一个有返回值,例如添加元素:
boolean add(E element) // 如果队列没满 ,将元素添加到队列的尾部并返回 true 。如果队列已满,抛出IllegalStateException
boolean offer(E element) // 如果队列没满 ,将元素添加到队列的尾部并返回 true 。如果队列已满,返回false
删除元素:
E remove() // 如果队列不为空 ,删除并返回这个队列头部的元素 。如果队列为空,抛出NoSuchElementException
E pool() // 如果队列不为空 ,删除并返回这个队列头部的元素 。如果队列为空,返回null
获取元素:
E element() // 如果队列不为空,返回这个队列头部的元素,但不删除。如果队列为空,抛出NoSuchElementException
E peek() // 如果队列不为空,返回这个队列头部的元素,但不删除。如果队列为空,返回null
双端队列Deque也是类似的API,可自行查询源码或API文档。

PriorityQueue
PriorityQueue可以以任意顺序插入集合。元素也都是必须能够比较的。PriorityQueue使用了一种称之为heap的数据结构,是一种可自我调节的二叉树,在执行add和remove操作时可以将最小的元素移动到根。PriorityQueue在调用remove方法时,总会获得当前队列中最小的元素,例如:
PriorityQueue<String> pq = new PriorityQueue<>();
pq.add("c");
pq.add("b");
pq.add("a");
while ( !pq.isEmpty()){
System.out .println(pq.remove()) ;
}
总是删除剩余队列中最小的元素。

HashMap和TreeMap
HashMap和TreeMap都是对key进行处理,HashMap对key进行hash,TreeMap用key的顺序来对元素进行排序。与HashSet和TreeSet一样,HashMap稍快一些,不关心排列顺序的情况下推荐使用HashMap。

使用keySet获取Map的所有key:
Map<String,String> map = new HashMap<>();
map.put("key1","value1");
map.put("key2","value1");
map.put("key3","value1");
Set<String> keys = map.keySet();
for(String key : keys){
System.out.println(key);
}
使用values方法获取所有value:
Collection<String> values = map.values();
for(String value : values){
System.out.println(value);
}
使用entrySet方法获取键值对集合:
Set<Map.Entry<String,String>> entries = map.entrySet();
for(Map.Entry<String,String> entry : entries){
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}




正文到此结束