集合——Map(Key不可重复,Value可重复)
执键写春秋 627 8

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的实例化对象,如下图所示: 集合——Map(Key不可重复,Value可重复)

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 是线程安全的吗,为什么不是线程安全的?死循环问题? 不是线性安全的。并发的情况下,扩容可能导致死循环问题。
评论区

索引目录