Map(Key不可重复,Value可重复)
备注:这里所说的Key不可重复,Value可重复不包括IdentityHashMap操作类。 Map是存放一对值的最大父接口,即接口中的而每个元素都是一对,以key→value的形式保存,每一对key→value都是一个Map.Entry对象的实例。Map常用的子类是HashMap、Hashtable、TreeMap。HashMap属于异步处理,性能较高;Hashtable属于同步处理,性能较低;TreeMap属于排序类,按照Comparable指定的顺序进行key排序。
Map.Entry简介 Map.Entry接口是Map内部定义的一个接口,专门用来保存key→value的内容,Map.Entry的定义如下:
public static interface Map.Entry<K,V>
对于集合来说,实际上是将key→value的数据保存在Map.Entry,然后再在Map集合中插入一个Map.Entry的实例化对象,如下图所示:
1.HashMap:数组+链表存储数据,线程不安全
HashMap基于键的HashCode值唯一标识一条数据,同时基于键的HashCode值进行数据的存取,因此可以快速地更新和查询数据,但其每次遍历的顺序无法保证相同。HashMap的key和value允许为null。
同时,HashMap是非线程安全的,即在同一时刻有多个线程同时写HashMap时可能导致数据的不一致。如需满足线程安全,可以用Collections的synchronizedMap方法使HashMap具有线程安全的能力。
1.1实例操作一:向集合中增加和取出内容
提示:在Map接口中使用put(K key,V value)方法可以向集合中增加内容,之后通过get(Object key)方法根据key找出其对应的value。
package person.xsc.datamanage;
import java.util.HashMap;
import java.util.Map;
public class HashMapDemo1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Map<String ,String> map=new HashMap<String,String>();
map.put("HelloWorld", "https://www.helloworld.net/");//增加内容
map.put("BaiDu", "http://www.baidu.com/");
String value=map.get("HelloWorld");//根据key取出value
System.out.println("根据指定的key取出的内容是:"+value);
}
}
1.2实例操作二:判断指定的key或value是否存在
提示:如果要判断某一个指定的key或value是否存在,可以使用Map接口提供的containsKey(Object key)和containsValue(Object value)两个方法,前者用于key判断,后者用于value判断。
package person.xsc.datamanage;
import java.util.HashMap;
import java.util.Map;
public class HashMapDemo2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Map<String ,String> map=new HashMap<String,String>();
map.put("HelloWorld", "https://www.helloworld.net/");//增加内容
map.put("BaiDu", "http://www.baidu.com/");
if(map.containsKey("HelloWorld")) {
System.out.println("搜索的Key存在!");
}else {
System.out.println("搜索的Key不存在!");
}
if(map.containsValue("https://cn.bing.com/")) {
System.out.println("搜索的Value存在!");
}else {
System.out.println("搜索的Value不存在!");
}
}
}
1.3实例操作三:输出全部key-value
提示:如果输出全部的key-value,可以使用entrySet()方法获取所有Map.Entry实例,然后遍历输出;也可以使用默认的toString直接输出;还可以使用迭代器方法。注意接收的set集合中指定的泛型要与Map中的泛型保持一致。
package person.xsc.datamanage;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashMapDemo3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Map<String ,String> map=new HashMap<String,String>();
map.put("HelloWorld", "https://www.helloworld.net/");//增加内容
map.put("BaiDu", "http://www.baidu.com/");
/*方法一:使用entrySet()方法获取所有Map.Entry实例*/
Set<Map.Entry<String, String>> maps =map.entrySet();
for (Map.Entry<String, String> entry : maps) {
System.out.println("Key="+entry.getKey()+",Value="+entry.getValue());
}
/*方法二:默认调用toString*/
System.out.println(map);
/*方法三:使用迭代器方法*/
Iterator<Map.Entry<String, String>> it=map.entrySet().iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
补充迭代器Iterator 简介:这里建议只要是碰到了集合输出的操作,就用Iterator接口(最标准的做法)。
publicinterfaceCollection<E>extendsIterable<E>{
Iterator<E> iterator();
方法如下:
- public boolean hasNext()方法检查集合中是否还有元素。
- public E next()方法获得当前元素。
- public void remove()方法删除当前元素。这里要注意:正常情况下,一个集合要把内容给Iterator输出,但是集合操作中也存在一个remove()方法,如果在使用Iterator输出时由集合对象调用了自身的删除方法,则会出现运行时迭代将出现错误,会停止输出。
2.HashTable:线程安全
HashTable是遗留类,也就是属于旧的操作类,HashMap是新的操作类,两者操作上没有什么特别大的区别。与HashMap不同的是,HashTable采用同步处理的方式,性能较低,同时,它不允许将key设置为null,否则将会出现Null Pointer Exception异常,但却是属于线程安全的操作类。从实际开发应用来看,HashMap类使用较多。3.TreeMap:基于二叉树数据结构
上面两个类在存放数据时并没有对其进行排序,TreeMap主要特点就是可以根据Key排序,默认按键值的升序排序,也可以自定义排序比较器。package person.xsc.datamanage; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; public class TreeMapDemo { public static void main(String[] args) { // TODO Auto-generated method stub Map<String ,String> map=new TreeMap<String,String>(); map.put("HelloWorld", "https://www.helloworld.net/");//增加内容 map.put("BaiDu", "http://www.baidu.com/"); map.put("AliBaBa", "https://www.alibaba.com/"); Set<String> keys=map.keySet(); Iterator<String> it=keys.iterator(); while(it.hasNext()) { String str=it.next(); System.out.println(str+"--->"+map.get(str)); } } } 输出: AliBaBa--->https://www.alibaba.com/ BaiDu--->http://www.baidu.com/ HelloWorld--->https://www.helloworld.net/
- 注意:使用自定义作为key时类需要实现Comparable接口。*
TreeMap可以依据key排序,上面的代码之所以没有出现Comparable,是因为代码使用String作为类,而在String类中本身就已经实现了Comparable接口,所以程序执行时不会有任何问题;而如果使用一个自定义的类作为Key,则此类必须实现Comparable接口,否则会抛出java.lang.ClassCastException异常。
4.关于Map的面试问题
- TreeMap底层? TreeMap实现了SotredMap接口,它是有序的集合。TreeMap底层数据结构是一个红黑树,每个key-value都作为一个红黑树的节点。如果在调用TreeMap的构造函数时没有指定比较器,则根据key执行自然排序。
- HashMap 是线程安全的吗,为什么不是线程安全的?死循环问题? 不是线性安全的。并发的情况下,扩容可能导致死循环问题。