前面给大家介绍了集合家族中的Collection家族,这一篇给大家分享的是集合中的另一个家族就是Map家族。以前的时候学习Map的时候没有很认真的去学习,我觉得很多东西还是不是很清楚。

这次我将总结的非常详细。程序员的道理里,我们风雨无阻!

一、Map接口

1.1、Map概述

  Map 的字面翻译是映射(地图就是一种映射)。将键映射到值的对象,一个映射不能包含重复的键(如果有添加有重复的键,后面的会覆盖掉前面的,但是如果是自定义类型必须重写hashCode()和equals()方法),每个键最多只能映射到一个值。

  map是Java中提供的一种通用的元素存储方式,它是一种集合类。map集合类用于存储键值对(“键”、“值”)即Map<key,value>,每个键映射到一个值。但要注意的是:key不能重复。所以通过指定的key就可以取出对应的value。

    

  在JavaSE中,对Map的实现主要包括: HashMap, TreeMap, HashTable 和 LinkedHashMap:

  • HashMap 使用哈希表(hash table)实现, 在 keys 和/或 values 之中,都是无序的.
  • TreeMap 基于红黑树(red-black tree)数据结构实现, 按 key 排序.
  • LinkedHashMap 保持者插入顺序.
  • Hashtable 与HashMap实现方式一样,但Hashtable属于同步(synchronized)的.

  所以如果代码是线程安全的,那么应该使用HashMap,因为Hashtable的同步是有一定量的运行代价的。而现今对于需要同步的Map,使用 ConcurrentHashMap 也比 Hashtable 有更高的效率。

  注:map中的key和value都必须是Object(除非指定了泛型)

1.2、Map接口和Collection接口的不同

  Map是双列的,Collection是单列的
  Map的键唯一,Collection的子体系Set是唯一的
  Map集合的数据结构值针对键有效,跟值无关;Collection集合的数据结构是针对元素有效。

  Map集合没有直接取出元素的方法,而是先转成Set集合,在通过迭代获取元素

1.3、Map集合功能概述

添加功能
* V put(K key,V value):添加元素。
* 如果键是第一次存储,就直接存储元素,返回null
* 如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值
       putAll(Map<? extends K,? extends V> m)将指定Map中的键值对复制到Map中
删除功能
* void clear():移除所有的键值对元素
* V remove(Object key):删除指定key所对应的键值对,返回可以所关联的value,如果key不存在,返回null
判断功能
* boolean containsKey(Object key):判断集合是否包含指定的键
* boolean containsValue(Object value):判断集合是否包含指定的值
* boolean isEmpty():判断集合是否为空
获取功能
* Set<Map.Entry<K,V>> entrySet():
* V get(Object key):根据键获取值
* Set<K> keySet():获取集合中所有键的集合
* Collection<V> values():获取集合中所有值的集合
长度功能
* int size():返回集合中的键值对的个数

  Map中包含一个内部类:Entry。该类封装了一个键值对,它包含了三个方法:

Object getKey():返回该Entry里包含的key值。
Object getValeu():返回该Entry里包含的value值。
Object setValue(V value):设置该Entry里包含的value值,并返回新设置的value值。

1.4、Map实例之遍历

  Map的遍历大体有3种:
    第一种:遍历Map.entrySet():它的每一个元素都是Map.Entry对象,这个对象中,放着的就是Map中的某一对key-value。
    第二种:遍历Map.keySet():它是Map中key值的集合,我们可以通过遍历这个集合来读取Map中的元素。
    第三种:遍历Map.values():它是Map中value的集合,我们可以直接通过这个集合遍历Map中的值,却不能读取key。

  1)Map集合的遍历之键找值

    思路:一是:获取所有键的集合。二是:遍历键的集合,获取到每一个键。三是:根据键找值。

package com.zyh.Collection.map;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set; public class MapDemo_0010 {
// Map集合的遍历之键找值
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("张三",);
map.put("美女",);
map.put("帅哥",);
map.put("流浪汉",); /*方式一:使用迭代器
Set<String> str = map.keySet();
Iterator<String> it = str.iterator();
while (it.hasNext()){
String key = it.next();
Integer value = map.get(key);
System.out.println("key="+key+"——value="+value);
}*/ //方式二:使用增强for循环
for (String key:map.keySet()){
System.out.println("key="+key+"——value="+map.get(key));
}
}
}

MapDemo_0010

  2)Map集合的遍历之键值对对象找键和值

    思路:一是:获取所有键值对对象的集合。二是:遍历键值对对象的集合,获取到每一个键值对对象。三是:根据键值对对象找键和值。

package com.zyh.Collection.map;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set; public class MapDemo_0011 {
//Map集合的遍历之键值对对象找键和值
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("张三",);
map.put("美女",);
map.put("帅哥",);
map.put("流浪汉",); /*方式一:使用迭代器
Set<Map.Entry<String, Integer>> entry = map.entrySet(); //获取所有的键值对象的集合
Iterator<Map.Entry<String, Integer>> it = entry.iterator(); //获取迭代器
while (it.hasNext()){
Map.Entry<String, Integer> en = it.next(); //获取键值对对象
String key = en.getKey(); //根据键值对对象获取键
Integer value = en.getValue(); //根据键值对对象获取值
System.out.println("key="+key+"——value="+value);
}*/
//方式二:使用增强for循环
for (Map.Entry<String,Integer> en : map.entrySet()){
String key = en.getKey();
Integer value = en.getValue();
System.out.println("key="+key+"——value="+value);
} }
}

MapDemo_0011

二、HashMap

2.1、HashMap概述  

  HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。它存储的时候是无序的。
  HashMap 继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口。
  HashMap 的实现不是同步的,这意味着它不是线程安全的。它的key、value都可以为null。此外,HashMap中的映射不是有序的。

  在java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。

    HashMap实际上是一个“链表的数组”的数据结构,每个元素存放链表头结点的数组,即数组和链表的结合体。

  

  HashMap注意事项:
    1)HashMap底层维护一个数组,我们向HashMap中所放置的对象实际上是存储在该数组当中。
    2)当向HashMap中put一对键值时,它会根据key的hashCode值计算出一个位置,该位置就是此对象准备往数组中存放的位置。

2.2、实例:在HashMap中存储key为Student对象,value为String类型  

  1)当键是自定义类型时怎么保证唯一性:重写hashCode()和equals()方法,这样我们在存储的时候如果有重复的键,后面的会覆盖后面的。

package com.zyh.Collection.map;

import com.zyh.domain.Student;
import java.util.HashMap; public class HashMapDemo_0010 {
public static void main(String[] args) {
HashMap<Student,String> hs = new HashMap<>();
hs.put(new Student("张三",),"上海");
hs.put(new Student("张三",),"上海");
hs.put(new Student("李四",),"深圳");
hs.put(new Student("王五",),"苏州");
hs.put(new Student("赵六",),"杭州"); System.out.println(hs);
}
}

  这里的话就会输出:

    

    分析:首先输出的都是无序的,为什么直接输出map就会打印呢?因为底层重写了toString方法。

    

    查看之后它的父类重写了toString()方法

2.3、HashMap的用法

  需求:统计字符串中每个字符出现的次数

    String str = "aaaabbbcccccccccc";
char[] arr = str.toCharArray(); //将字符串转换成字符数组
HashMap<Character, Integer> hm = new HashMap<>(); //创建双列集合存储键和值 for(char c : arr) { //遍历字符数组
if(!hm.containsKey(c)) { //如果不包含这个键
hm.put(c, ); //就将键和值为1添加
}else { //如果包含这个键
hm.put(c, hm.get(c) + ); //就将键和值再加1添加进来
} //hm.put(c, !hm.containsKey(c) ? 1 : hm.get(c) + 1);
Integer i = !hm.containsKey(c) ? hm.put(c, ) : hm.put(c, hm.get(c) + );
} for (Character key : hm.keySet()) { //遍历双列集合
System.out.println(key + "=" + hm.get(key));
}

2.4、LinkedHashMap

  特点:底层是链表实现的可以保证怎么存就怎么取

  实例:

package com.zyh.Collection.map;

import com.zyh.domain.Student;
import java.util.LinkedHashMap; public class LinkedHashMapDemo_0010 {
public static void main(String[] args) {
LinkedHashMap<Student,String> lhs = new LinkedHashMap<>();
lhs.put(new Student("张三",),"上海");
lhs.put(new Student("李四",),"深圳");
lhs.put(new Student("王五",),"苏州");
lhs.put(new Student("赵六",),"杭州"); System.out.println(lhs);
}
}

  结果:

      

四、TreeMap

4.1、TreeMap概述

  TreeMap底层是二叉树数据结构,线程不同步,可用于给Map集合中的键进行排序。

  注意:
    1)用作key的对象必须实现hashCode和equals方法。
    2)不能保证其中的键值对的顺序
    3)尽量不要使用可变对象作为它们的key值。

  SortedMap接口和TreeMap类的关系

    SortedMap接口是Map的子接口,其进一步提供对于键的排序功能。
    TreeMap类就是SortedMap接口的实现类。
    TreeMap可以对key值进行自然排序或者比较器排序,其用法和TreeSet是一致的。

4.2、用例子来说明TreeMap排序问题

package com.zyh.Collection.map;

import com.zyh.domain.Student;
import java.util.TreeMap; public class TreeMapDemo_0010 {
public static void main(String[] args) {
TreeMap<Student,String> tm = new TreeMap<>();
tm.put(new Student("张三",),"上海");
tm.put(new Student("李四",18),"深圳");
tm.put(new Student("王五",),"苏州");
tm.put(new Student("赵六",66),"杭州");
System.out.println(tm);
}
}

 当我们执行的时候会出错:

    

  因为key是自定义对象不知道怎么排序,所以这里要实现Comparable接口,重写compareTo方法,或者给TreeMap的构造方法中声明一个比较器。

    方式一:实现Comparable接口,重写compareTo方法

      实现Comparable接口:

      

      重写compareTo方法:

      

      结果:按年龄排序

      

    方式二:给TreeMap的构造方法中声明一个比较器(测试前把前面Student中的删除掉)     

package com.zyh.Collection.map;

import com.zyh.domain.Student;
import java.util.Comparator;
import java.util.TreeMap; public class TreeMapDemo_0010 {
public static void main(String[] args) {
TreeMap<Student,String> tm = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s1.getAge()-s2.getAge();
//s1.getName().compareTo(s2.getName())这里的compareTo方法是String类中的方法
return num==?s1.getName().compareTo(s2.getName()):num;
}
});
tm.put(new Student("张三",),"上海");
tm.put(new Student("李四",),"深圳");
tm.put(new Student("王五",),"苏州");
tm.put(new Student("赵六",),"杭州");
System.out.println(tm);
}
}

五、HashMap与HashTable的区别

5.1、同步性

  Hashtable是同步的,这个类中的一些方法保证了Hashtable中的对象是线程安全的。而HashMap则是异步的,因此HashMap中的对象并不是线程安全的。
  因为同步的要求会影响执行的效率,所以如果你不需要线程安全的集合那么使用HashMap是一个很好的选择,这样可以避免由于同步带来的不必要的性能开销,从而提高效率。

5.2、值

  HashMap可以让你将空值作为一个表的条目的key或value,但是Hashtable是不能放入空值的。HashMap最多只有一个key值为null,但可以有无数多个value值为null。

5.3、性能

  HashMap的性能最好,HashTable的性能是最差(因为它是同步的)    

    

觉得不错的点个“推荐”哦!!!

JavaSE集合(八)之Map的更多相关文章

  1. [javaSE] 集合框架(Map概述)

    Map集合,将key对象映射到value对象 三个主要的子类:Hashtable,HashMap,TreeMap Hashtable:底层是哈希表数据结构,不允许使用null值,线程同步 HashMa ...

  2. JavaSE集合(十)之Map

    前面给大家介绍了集合家族中的Collection家族,这一篇给大家分享的是集合中的另一个家族就是Map家族.以前的时候学习Map的时候没有很认真的去学习,我觉得很多东西还是不是很清楚. 这次我将总结的 ...

  3. JavaSE(八)之集合概述

    前几天其实一直在学习关于linux的内容和kvm虚拟化的知识.今天有时间来回顾一下集合相关的知识,接下来我将带大家一起来回顾一起集合关联的知识. 不要辜负自己花费时间做的事情,只有用心才能得到真心的回 ...

  4. JavaSE(八)之Map总结

    上一篇是总结了Collection接口的各种实现类,这一篇我将分享的是Map的总结,希望大家点评! 一.Map接口 1.1.为什么Collection不能满足集合的所有功能? Collection接口 ...

  5. Java 集合系列 15 Map总结

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  6. Java中的集合(十一) 实现Map接口的TreeMap

    Java中的集合(十一) 实现Map接口的TreeMap 一.TreeMap简介(基于JDK1.8) TreeMap是基于红黑树数据结构,是一个key-value的有序集合,该映射根据其键的自然顺序进 ...

  7. Java中的集合(七)双列集合顶层接口------Map接口架构

    Java中的集合(七)双列集合顶层接口------Map接口 一.Map接口的简介 通过List接口,我们知道List接口下的集合是单列集合,数据存储是单列的结构.Map接口下是一个键值对(key-v ...

  8. javase集合 温故而知新

    复习javase集合 1.为什么要有集合? 数组长度需要在初始化时确定大小,数据结构单一.因此集合出现了 2.数组和集合的区别 区别一:数组既可以存储基本数据类型,又可以存储引用类型,集合只能存储引用 ...

  9. Java集合框架之map

    Java集合框架之map. Map的主要实现类有HashMap,LinkedHashMap,TreeMap,等等.具体可参阅API文档. 其中HashMap是无序排序. LinkedHashMap是自 ...

随机推荐

  1. 【转】在ASP.NET应用启动的时候初始化的几种方法

    ASP.NET 4.0 之前,有两种方法:通过Global.asax 中的 Application_Start 事件启动,或者通过定义在 App_Code 文件夹中任意类中的AppInitialize ...

  2. 使用UINavigationController后导致UIScollView尺寸变化

    转自:http://www.w3c.com.cn/%E4%BD%BF%E7%94%A8uinavigationcontroller%E5%90%8E%E5%AF%BC%E8%87%B4uiscollv ...

  3. 进程的处理器亲和性和 vCPU 的绑定(查看cpu信息,超线程等)

    通常情况下,在 SMP 系统中,Linux 内核的进程调度器根据自有的调度策略将系统中的一个进程调度到某个 CPU 上执行.一个进程在前一个执行时间是在 cpuM(M 为系统中的某 CPU 的 ID) ...

  4. 设置PDF文件默认缩放比例

  5. Installation error: INSTALL_FAILED_INSUFFICIENT_STORAGE 解决方法

    最近在做真机测试的时候,经常出现Installation error: INSTAL L_FAILED_INSUFFICIENT_STORAGE这个问题,导致apk没法安装到是手机上,在eclipse ...

  6. 每日英语:Best Ways to Ramp Up to A Marathon

    For the record number of American runners who completed an official race event last year, the questi ...

  7. Livepool

    LivePool Fiddler Like cross platform debugging proxy for web developers base on NodeJS LivePool 是一个基 ...

  8. C# 延时函数 非Sleep

    1.示例: using System.Runtime.InteropServices; [DllImport("kernel32.dll")] static extern uint ...

  9. 使用filter导致服务器返回的页面始终是空白---在doFilter中漏写了chain.doFilter()

    今天调代码的时候,突然发现,服务器开着,什么都没有问题,当我把下面这个filter给deploy了以后,访问所有的页面就都是空白. 后来发现,是因为在代码路径中,有一条路径没有调用filterChai ...

  10. java.io.PrintWriter 中 write() 与 print() 的区别

    最终都是重写了抽象类Writer里面的write方法print方法可以将各种类型的数据转换成字符串的形式输出.重载的write方法只能输出字符.字符数组.字符串等与字符相关的数据.