一、本章要点
- 了解Java集合框架的层次架构
- Collection接口
- 熟悉Set接口,了解何时及如何使用HashSet、LinkedHashSet来存储元素
- 熟悉List接口,了解何时及如何使用ArrayList或LinkedList来存储元素
- 熟悉Map接口,了解何时及如何使用HashMap、LinkedHashMap与HashTable来存储带键值的值
- 其他常用API
1.集合框架构成
一个集合(collection)就是一个存储一组对象的容器,一般将这些对象称为集合的元素(element)。 Java集合构架支持三种类型的集合:规则集(set)、线性表(list)和图(map),它们分别定义在接口Set、List与Map中。Set的实例存储一组互不相同的元素,List的实例存储一组顺序排列的元素,Map的实例存储一组对象,每个对象都有一个关联的键值。
2.Collection接口
Collection接口是处理对象集合的根接口,它定义了如下方法:
func | desc |
---|---|
+add(Object o):boolean | 向该集合中添加一个元素 |
+addAll(Collection c):boolean | 将c添加进另一个集合(并集) |
+clear():void | 删除集合中的所有元素 |
+contains(Object o):boolean | 集合包含元素o则返回true |
+containsAll(Collection c):boolean | 包含c中的所有元素则返回true |
+equals(Object o):boolean | 等于另一个集合则返回true |
+hashCode():int | 返回散列码 |
+isEmpty():boolean | 没有元素则返回true |
+iterator():Iterator | 返回集合中元素的迭代探子 |
+remove(Object o):boolean | 删除集合中元素o |
+removeAll(Collection c):boolean | 删除在c中的元素(差集) |
+retainAll(Collection c):boolean | 保留该集合与指定集合中所有相同的元素(交集) |
+size():int | 返回集合中元素的个数 |
+toArray():Object[] | 返回所有集合元素所构成对象数组 |
+toArray(Object[] array):Object[] | 返回使用集合中指定元素构成对象数组 |
3.规则集Set
Set实例不能包含相同的元素,主要有HashSet、LinkedHashSet
- HashSet
HashSet存储互不相同的元素(各个元素的散列码值不能相同)。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public static void main(String[] args) {
Set hashSet = new HashSet();
String str = "select run_date from fm_system where run_date = '20991231'";
StringTokenizer tokenizer = new StringTokenizer(str, " ");
while (tokenizer.hasMoreTokens()) {
hashSet.add(tokenizer.nextElement());
}
System.out.println(hashSet);
Iterator<String> it = hashSet.iterator();
while (it.hasNext()) {
System.out.print(it.next() + " , ");
}
}
run_date出现了两次,但是只有一个被存储,因为规则集不允许重复元素存在。
- 链式存储LinkedHashSet
它使用链表存储(见单链表)实现了对HashSet类的扩展,支持规则集内元素的排序。在HashSet中元素是没有顺序的,而在LinkedHashSet中,可以按元素插入集合的顺序进行提取。
如果不需要元素按照插入的顺序进行存储,应该使用HashSet,它的效率较高。
4.线性表List
与Set的区别是,线性表不仅可以存储重复元素,还可以指定元素的位置,用户可以使用下标来访问它们。相比Collection接口,List接口中定义了如下新方法:
func | desc |
---|---|
+add(int index,Object o):boolean | 向指定位置添加一个元素 |
+addAll(int index,Collection c):boolean | 向指定位置添加一个集合对象 |
+get(int index):Object | 返回线性表指定下标处的元素 |
+indexOf(Object o):int | 返回与指定元素匹配的第一个元素的下标 |
+lastIndexOf(Object o):int | 返回与指定元素匹配的最后一个元素的下标 |
+listIterator():ListIterator | 返回线性表元素的迭代子 |
+listIterator(int startIndex):ListIterator | 返回线性表元素从startIndex开始的迭代子 |
+remove(int index):boolean | 删除指定下标的元素 |
+set(int index,Object o):Object | 设置指定下标的元素,返回原值 |
+subList(int form,int end):List | 返回从form到end的元素构成的线性表 |
ArrayList与LinkedList
ArrayList将数据元素存储在一个数组中,该数组是动态创建的。在增加元素时如果数组容量超限,则自动创建一个更大的数组并将当前数组中的所有元素复制到新数组中。
ArrayList的常用创建方式有三种:
- new ArrayList();
- new ArrayList(Collection c);
- new ArrayList(int initialCapacity);
LinkedList将元素存储在链表尾部,元素的存储空间可以不连续。
- 如果需要高频率地删除或插入结点,应该使用LinkedList。
- 如果有较多查询操作,应该使用ArrayList。
更多关于两者的区别见数据结构-线性表
5.图Map
Map接口建立元素和键值的一个映射关系。在Map中,键值可以是任意类型的对象。一个图中不能有重复的键值,每个键值对应一个值。Map接口提供对一个值的集合与一个键值的规则集进行查询、更新和读取等方法:
func | desc |
---|---|
+containsKey(Object key):boolean | 图中是否包含键key |
+containsValue(Object value):boolean | 图中是否包含值value |
+entrySet():Set | 返回图中实体构成的规则集 |
+get(Object key):Object | 返回指定键对应的值 |
+keySet():Set | 返回图中键构成的规则集 |
+put(Object key,Object value):Object | 添加一个键值对 |
+putAll(Map m):void | 添加一个map |
+remove(Object key):Object | 删除指定键的映射 |
+values():Collection | 返回由该图中的值构成的集合 |
Map的遍历1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35//适用于同时需要key和value的场景
public void func1(Map<Integer, Integer> map) {
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
System.out.println("Key:" + entry.getKey() + ",Value:" + entry.getValue());
}
}
//适用于只需要key或者只需要value
public void func2(Map<Integer, Integer> map) {
for (Integer key : map.keySet()) {
System.out.println("Key:" + key);
}
for (Integer value : map.values()) {
System.out.println("value:" + value);
}
}
//使用Iterator遍历
public void func3(Map<Integer, Integer> map) {
Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, Integer> entry = it.next();
System.out.println("key:" + entry.getKey() + ",value:" + entry.getValue());
}
}
//通过key拉访问value
public void func4(Map<Integer, Integer> map) {
for (Integer key : map.keySet()) {
Integer value = map.get(key);
System.out.println("Key:" + key + ",Value:" + value);
}
}
同时需要key和value推荐使用第一种(第四种效率太低),只需要key或者value使用第二种;
HashMap与HashTable的区别
(1)、Null的支持
- HashMap的key和value都允许为Null,key为Null的键值永远都放在table[0]为头结点的链表中。
- HashTable既不支持Null key也不支持Null value。
(2)、线程安全性 - HashTable是线程安全的,它的方法都加入了synchronize关键字。
- HashMap在多线程环境下会出现死锁、不安全的情况,对应可以使用ConcurrentHashMap处理。
(3)、初始容量和容量扩充 - HashMap默认的初始化容量为16,每次扩容后变为原来的2倍
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; //HashMap初始化容量 16 - HashTable默认容量为11,每次扩容后变为原来的2n+1
(4)、计算hash值的方式不同 HashTable直接使用对象的hashCode值,然后除长度留余数来获得最终的元素位置。显然除法运算是很耗时的。
1
2
3//HashTable取hash方式
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;HashMap为了提高计算效率,将哈希表的大小固定为2的幂,这样取模运算时,不需要除法只用移位运算即可,明显提高效率。
1
2
3
4static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
6.其他常用API
- Stack类的常用方法:
func | desc |
---|---|
+empty():boolean | 栈为空时返回true |
+peek():Object | 返回栈顶元素 |
+pop():Object | 返回并删除栈顶元素 |
+push(Object o):Object | 入栈 |
+search(Object o):int | 返回指定元素在栈中的位置 |
- Arrays类的常用方法
Arrays类中包含对数组进行排序、查找、比较和填充元素的各种静态方法,它还包含了将数组转为线性表的方法。
func | desc |
---|---|
+asList(Object[] a):List | 用对象数组返回一个线性表 |
+binarySearch(int[] a, int key):int | 一系列重载二分查找法 |
+fill(Object[],int a,int b):void | 一系列重载填充方法 |
+sort(int[] a, int fromIndex, int toIndex):void | 一系列重载的排序方法 |
本文链接: http://www.xiaopeng.pro/articles/e720f1c8.html
版权声明: 本原创文章采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!