HashMap、HashTable、LinkedHashMap和TreeMap用法和区别
Java为数据结构中的映射定义了一个接口java.util.Map,它有四个实现类,分别是HashMap、HashTable、LinkedHashMap和TreeMap。本节实例主要介绍这4中实例的用法和区别。
关键技术剖析:
Map用于存储键值对,根据键得到值,因此不允许键重复,值可以重复。
l (1)HashMap是一个最常用的Map,它根据键的hashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。HashMap最多只允许一条记录的键为null,不允许多条记录的值为null。HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。如果需要同步,可以用Collections.synchronizedMap(HashMap map)方法使HashMap具有同步的能力。
l (2)Hashtable与HashMap类似,不同的是:它不允许记录的键或者值为空;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,然而,这也导致了Hashtable在写入时会比较慢。
l (3)LinkedHashMap保存了记录的插入顺序,在用Iteraor遍历LinkedHashMap时,先得到的记录肯定是先插入的。在遍历的时候会比HashMap慢。有HashMap的全部特性。
l (4)TreeMap能够把它保存的记录根据键排序,默认是按升序排序,也可以指定排序的比较器。当用Iteraor遍历TreeMap时,得到的记录是排过序的。TreeMap的键和值都不能为空。
关键技术剖析:
Map用于存储键值对,根据键得到值,因此不允许键重复,值可以重复。
l (1)HashMap是一个最常用的Map,它根据键的hashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。HashMap最多只允许一条记录的键为null,不允许多条记录的值为null。HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。如果需要同步,可以用Collections.synchronizedMap(HashMap map)方法使HashMap具有同步的能力。
l (2)Hashtable与HashMap类似,不同的是:它不允许记录的键或者值为空;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,然而,这也导致了Hashtable在写入时会比较慢。
l (3)LinkedHashMap保存了记录的插入顺序,在用Iteraor遍历LinkedHashMap时,先得到的记录肯定是先插入的。在遍历的时候会比HashMap慢。有HashMap的全部特性。
l (4)TreeMap能够把它保存的记录根据键排序,默认是按升序排序,也可以指定排序的比较器。当用Iteraor遍历TreeMap时,得到的记录是排过序的。TreeMap的键和值都不能为空。
001 |
import java.util.HashMap; |
002 |
import java.util.Hashtable; |
003 |
import java.util.Iterator; |
004 |
import java.util.LinkedHashMap; |
005 |
import java.util.Map; |
006 |
import java.util.TreeMap; |
007 |
|
008 |
|
009 |
public class TestMap
{ |
010 |
|
011 |
|
012 |
public static void init(Map
map){ |
013 |
if (map
!= null ){ |
014 |
String
key = null ; |
015 |
for ( int i= 5 ;
i> 0 ;
i--){ |
016 |
key
= new Integer(i).toString()
+ ".0" ; |
017 |
map.put(key,
key.toString()); |
018 |
//Map中的键是不重复的,如果插入两个键值一样的记录, |
019 |
//那么后插入的记录会覆盖先插入的记录 |
020 |
map.put(key,
key.toString() + "0" );
} |
021 |
} |
022 |
} |
023 |
|
024 |
public static void output(Map
map){ |
025 |
if (map
!= null ){ |
026 |
Object
key = null ; |
027 |
Object
value = null ; |
028 |
//使用迭代器遍历Map的键,根据键取值 |
029 |
Iterator
it = map.keySet().iterator(); |
030 |
while (it.hasNext()){ |
031 |
key
= it.next(); |
032 |
value
= map.get(key); |
033 |
System.out.println( "key:
" +
key + ";
value: " +
value ); |
034 |
} |
035 |
//或者使用迭代器遍历Map的记录Map.Entry |
036 |
Map.Entry
entry = null ; |
037 |
it
= map.entrySet().iterator(); |
038 |
while (it.hasNext()){ |
039 |
//一个Map.Entry代表一条记录 |
040 |
entry
= (Map.Entry)it.next(); |
041 |
//通过entry可以获得记录的键和值 |
042 |
//System.out.println("key:
" + entry.getKey() + "; value: " + entry.getValue()); |
043 |
} |
044 |
} |
045 |
} |
046 |
|
047 |
public static boolean containsKey(Map
map, Object key){ |
048 |
if (map
!= null ){ |
049 |
return map.containsKey(key); |
050 |
} |
051 |
return false ; |
052 |
} |
053 |
|
054 |
public static boolean containsValue(Map
map, Object value){ |
055 |
if (map
!= null ){ |
056 |
return map.containsValue(value); |
057 |
} |
058 |
return false ; |
059 |
} |
060 |
|
061 |
public static void testHashMap(){ |
062 |
Map
myMap = new HashMap(); |
063 |
init(myMap); |
064 |
//HashMap的键可以为null |
065 |
myMap.put( null , "ddd" ); |
066 |
//HashMap的值可以为null |
067 |
myMap.put( "aaa" , null ); |
068 |
output(myMap); |
069 |
} |
070 |
|
071 |
public static void testHashtable(){ |
072 |
Map
myMap = new Hashtable(); |
073 |
init(myMap); |
074 |
//Hashtable的键不能为null |
075 |
//myMap.put(null,"ddd"); |
076 |
//Hashtable的值不能为null |
077 |
//myMap.put("aaa",
null); |
078 |
output(myMap); |
079 |
} |
080 |
|
081 |
public static void testLinkedHashMap(){ |
082 |
Map
myMap = new LinkedHashMap(); |
083 |
init(myMap); |
084 |
//LinkedHashMap的键可以为null |
085 |
myMap.put( null , "ddd" ); |
086 |
myMap.put( null , "aaa" ); |
087 |
//LinkedHashMap的值可以为null |
088 |
myMap.put( "aaa" , null ); |
089 |
output(myMap); |
090 |
} |
091 |
|
092 |
public static void testTreeMap(){ |
093 |
Map
myMap = new TreeMap(); |
094 |
init(myMap); |
095 |
//TreeMap的键不能为null |
096 |
//myMap.put(null,"ddd"); |
097 |
//TreeMap的值不能为null |
098 |
//myMap.put("aaa",
null); |
099 |
output(myMap); |
100 |
} |
101 |
|
102 |
public static void main(String[]
args) { |
103 |
System.out.println( "采用HashMap" ); |
104 |
TestMap.testHashMap(); |
105 |
System.out.println( "采用Hashtable" ); |
106 |
TestMap.testHashtable(); |
107 |
System.out.println( "采用LinkedHashMap" ); |
108 |
TestMap.testLinkedHashMap(); |
109 |
System.out.println( "采用TreeMap" ); |
110 |
TestMap.testTreeMap(); |
111 |
|
112 |
Map
myMap = new HashMap(); |
113 |
TestMap.init(myMap); |
114 |
System.out.println( "新初始化一个Map:
myMap" ); |
115 |
TestMap.output(myMap); |
116 |
//清空Map |
117 |
myMap.clear(); |
118 |
System.out.println( "将myMap
clear后,myMap空了么? " +
myMap.isEmpty()); |
119 |
TestMap.output(myMap); |
120 |
myMap.put( "aaa" , "aaaa" ); |
121 |
myMap.put( "bbb" , "bbbb" ); |
122 |
//判断Map是否包含某键或者某值 |
123 |
System.out.println( "myMap包含键aaa?
" +
TestMap.containsKey(myMap, "aaa" )); |
124 |
System.out.println( "myMap包含值aaaa?
" +
TestMap.containsValue(myMap, "aaaa" )); |
125 |
//根据键删除Map中的记录 |
126 |
myMap.remove( "aaa" ); |
127 |
System.out.println( "删除键aaa后,myMap包含键aaa?
" +
TestMap.containsKey(myMap, "aaa" )); |
128 |
//获取Map的记录数 |
129 |
System.out.println( "myMap包含的记录数:
" +
myMap.size()); |
130 |
} |
131 |
} |
132 |
|
133 |
输出结果: |
134 |
采用HashMap |
135 |
key: null ;
value: ddd |
136 |
key: 3.0 ;
value: 3.00 |
137 |
key:
aaa; value: null |
138 |
key: 4.0 ;
value: 4.00 |
139 |
key: 1.0 ;
value: 1.00 |
140 |
key: 5.0 ;
value: 5.00 |
141 |
key: 2.0 ;
value: 2.00 |
142 |
采用Hashtable |
143 |
key: 4.0 ;
value: 4.00 |
144 |
key: 1.0 ;
value: 1.00 |
145 |
key: 3.0 ;
value: 3.00 |
146 |
key: 5.0 ;
value: 5.00 |
147 |
key: 2.0 ;
value: 2.00 |
148 |
采用LinkedHashMap |
149 |
key: 5.0 ;
value: 5.00 |
150 |
key: 4.0 ;
value: 4.00 |
151 |
key: 3.0 ;
value: 3.00 |
152 |
key: 2.0 ;
value: 2.00 |
153 |
key: 1.0 ;
value: 1.00 |
154 |
key: null ;
value: aaa |
155 |
key:
aaa; value: null |
156 |
采用TreeMap |
157 |
key: 1.0 ;
value: 1.00 |
158 |
key: 2.0 ;
value: 2.00 |
159 |
key: 3.0 ;
value: 3.00 |
160 |
key: 4.0 ;
value: 4.00 |
161 |
key: 5.0 ;
value: 5.00 |
162 |
新初始化一个Map:
myMap |
163 |
key: 3.0 ;
value: 3.00 |
164 |
key: 4.0 ;
value: 4.00 |
165 |
key: 1.0 ;
value: 1.00 |
166 |
key: 5.0 ;
value: 5.00 |
167 |
key: 2.0 ;
value: 2.00 |
168 |
将myMap
clear后,myMap空了么? true |
169 |
myMap包含键aaa? true |
170 |
myMap包含值aaaa? true |
171 |
删除键aaa后,myMap包含键aaa? false |
172 |
myMap包含的记录数: 1 |
173 |
|
174 |
源码分析: |
175 |
遍历Map有两种方法: |
176 |
( 1 )map的keySet()方法获得键的集合,再调用键集合的iterator方法获得键的迭代器,以此迭代地取出Map中的键,用get方法获得键对应的值,便完成了Map的遍历。代码如下所示: |
177 |
//使用迭代器遍历Map的键,根据键取值 |
178 |
Iterator
it = map.keySet().iterator(); |
179 |
while (it.hasNext()){ |
180 |
key
= it.next(); |
181 |
value
= map.get(key); |
182 |
System.out.println( "key:
" +
key + ";
value: " +
value ); |
183 |
} |
184 |
( 2 )使用Map的entrySet方法获得Map中记录的集合,每条对象都是一个Map.Entry对象,使用其getKey方法获得记录的键,使用其getValue方法获得记录的值。代码如下所示: |
185 |
//或者使用迭代器遍历Map的记录Map.Entry |
186 |
Map.Entry
entry = null ; |
187 |
it
= map.entrySet().iterator(); |
188 |
while (it.hasNext()){ |
189 |
//一个Map.Entry代表一条记录 |
190 |
entry
= (Map.Entry)it.next(); |
191 |
//通过entry可以获得记录的键和值 |
192 |
//System.out.println("key:
" + entry.getKey() + "; value: " + entry.getValue() |
如果你喜欢本文, 请长按二维码,关注公众号 分布式编程.
作者:分布式编程
出处:https://zthinker.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。