一、概述

1.Map是一种接口,在JAVA集合框架中是以一种非常重要的集合。
2.Map一次添加一对元素,所以又称为“双列集合”(Collection一次添加一个元素,所以又称为“单列集合”)
3.Map集合中存放的是一个一个的键值对,集合中存放的元素必须保证键的唯一性。

二、常用方法

1.添加

 V put(K key, V value) 
          将指定的值与此映射中的指定键关联(可选操作)。

该方法的作用就是向集合中添加一个键值对,并返回一个值;如果键存在,则返回对应的旧值,并以新值取代之;如果键不存在则返回null。所以该方法也是修改的方法。

void putAll(Map<? extends K,? extends V> m) 
          从指定映射中将所有映射关系复制到此映射中(可选操作)。

该方法功能略,但注意泛型上限的使用。比较Collection方法:

 boolean addAll(Collection<? extends E> c) 
          将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。

2.删除

 V remove(Object key) 
          如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。

该方法根据键删除一个键值对,并返回值。如果没有这个键值对,将返回null。

 void clear() 
          从此映射中移除所有映射关系(可选操作)。

该方法功能就是清空集合。
3.判断

 boolean containsKey(Object key) 
          如果此映射包含指定键的映射关系,则返回 true
 boolean containsValue(Object value) 
          如果此映射将一个或多个键映射到指定值,则返回 true

这两个方法,前者判断是否存在指定键,后者判断是否存在指定值。

 boolean isEmpty() 
          如果此映射未包含键-值映射关系,则返回 true

该方法用于判断该Map集合是否为空集合。
4.获取。

 V get(Object key) 
          返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null
 int size() 
          返回此映射中的键-值映射关系数。

这两个方法,前者根据指定的键获取对应的值,如果集合中没有指定的键,则返回null;后者获取键值对的个数。

以上的方法为基本方法,重点方法在下面。

三、重点:Map集合的四种遍历方式

1.第一种遍历方式:使用keySet方法

 Set<K> keySet() 
          返回此映射中包含的键的 Set 视图。

该方法会返回一个包含所有键的Set集合。

遍历过程:先得到所有键的集合,遍历集合,根据键得到所有的值。

package p01.traverseDemo01.keySetDemo;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set; public class KeySetDemo { public static void main(String[] args) {
Demo01();
} private static void Demo01() {
Map<Integer,String>map=new HashMap<Integer,String>();
map.put(1, "wangcai");
map.put(2, "xiaoqiang");
map.put(3, "xiaoming"); Set<Integer>set=map.keySet();
for(Iterator<Integer>it=set.iterator();it.hasNext();)
{
Integer key=it.next();
String value=map.get(key);
System.out.println(key+":"+value);
} } }

应当注意,结果是无序的,这是因为采用了HashMap作为示例,HashMap底层的数据结构是哈希表,存储元素的时候有自己的规则,所以无序。

2.第二种遍历方式:使用entrySet方法

 Set<Map.Entry<K,V>> entrySet() 
          返回此映射中包含的映射关系的 Set 视图。

此方法返回值也是一个Set集合,但是存储的内容是Map.Entry对象。Map.Entry是什么东西?

JDK1.6API的解释如下:

嵌套类摘要
static interface Map.Entry<K,V> 
          映射项(键-值对)。

虽然API的解释是“嵌套类”,但是Map是一个接口,Entry也是一个接口,事实上Map.Entry是Map的一个内部静态接口。

该接口封装了几个方法,用于操作一个键值对,注意,是一个,因为它仅仅对一个键值对进行封装(确切的说是对操作每个键值对的方法进行了封装,每个键值对对应着一个Map.Entry对象)。

Map.Entry接口的方法如下:

方法摘要
 boolean equals(Object o) 
          比较指定对象与此项的相等性。
 K getKey() 
          返回与此项对应的键。
 V getValue() 
          返回与此项对应的值。
 int hashCode() 
          返回此映射项的哈希码值。
 V setValue(V value) 
          用指定的值替换与此项对应的值(可选操作)。

以上方法中,最常用的是getKey方法和getValue方法。

遍历过程:首先拿到每一个键值对对象Map.Entry的集合,再通过遍历集合拿到所有的键值对。

package p01.traverseDemo01.keySetDemo;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set; public class KeySetDemo { public static void main(String[] args) {
Demo01();
} private static void Demo01() {
Map<Integer,String>map=new HashMap<Integer,String>();
map.put(1, "wangcai");
map.put(3, "xiaoming");
map.put(2, "xiaoqiang"); Set<Integer>set=map.keySet();
for(Iterator<Integer>it=set.iterator();it.hasNext();)
{
Integer key=it.next();
String value=map.get(key);
System.out.println(key+":"+value);
} } }

3.第三种遍历方式:使用values方法

 Collection<V> values() 
          返回此映射中包含的值的 Collection 视图。

此种方法可以返回值的Collection集合,比较返回值,第一种方式使用keySet方法,返回值类型是Set集合,这里为什么不是Set集合?

解析:Map中键是唯一的,所以使用Set集合存储,而值可以重复,所以使用Collection集合存储。

package p01.traverseDemo03.valuesDemo;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set; public class ValuesDemo { public static void main(String[] args) {
Demo01();
} private static void Demo01() {
Map<Integer,String>map=new HashMap<Integer,String>();
map.put(1, "wangcai");
map.put(3, "xiaoming");
map.put(2, "xiaoqiang"); Collection<String>coll=map.values();
for(Iterator<String>it=coll.iterator();it.hasNext();)
{
String value=it.next();
System.out.println(value);
} } }

4.第四种遍历方式:使用增强型for循环间接遍历。

package p11.ArraysDemo.p01.ExtendForCircle;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set; /**
* 使用增强型for循环实现Map的三种遍历方式
* @author kuangdaoyizhimei
*
*/
public class ExtendForCircle { public static void main(String[] args) {
Map<Integer,String>map=new HashMap<Integer,String>();
map.put(1, "xiaoqiang");
map.put(2, "zhangsan");
map.put(3, "lisi");
map.put(4, "wangwu");
Function1(map);
Function2(map);
Function3(map);
} private static void Function3(Map<Integer, String> map) {
Set<Map.Entry<Integer, String>>set=map.entrySet();
for(Map.Entry<Integer, String>kv:set)
{
Integer key=kv.getKey();
String value=kv.getValue();
System.out.println("Key:"+key+"\tvalue:"+value);
}
} private static void Function2(Map<Integer, String> map) {
Collection<String>list=map.values();
for(String val:list)
{
System.out.println(val);
}
System.out.println();
System.out.println();
} private static void Function1(Map<Integer, String> map) {
Set<Integer>set=map.keySet();
for(Integer i:set)
{
System.out.println(i+":"+map.get(i));
}
System.out.println();
System.out.println();
} }

四、Map集合的常见子类

public class Hashtable<K,V>extends Dictionary<K,V>implements Map<K,V>, Cloneable, Serializable
public class HashMap<K,V>extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable
public class TreeMap<K,V>extends AbstractMap<K,V>implements NavigableMap<K,V>, Cloneable, Serializable

这三者有些区别:

HashTable:内部结构是哈希表,JDK1.0就出现了(JDK1.0出现的单列集合只有Vector,双列集合只有HashTable),是同步的。不允许null作为键值。
HashMap:内部结构是哈希表,是非同步的。允许null作为键值。
TreeMap:内部结构是一棵红黑树,可以对Map集合中的键进行排序。

需要注意的是Set集合的实现依赖于HashMap集合----HashMap将值统一为一个对象而只关注键的操作即可实现Set集合中元素的唯一性。

HashTable有一个子类应当特别注意:Properties

public class Propertiesextends Hashtable<Object,Object>

这个类用来存储键值对型的文件配置信息,它和Io技术相结合才能发挥出它的优势。

1.HashMap类。

Hash代表着底层的实现使用了哈希表,所以如果使用自定义对象作为键,应当注意重写类的hashCode方法和equals方法。

示例:使用HashMap存储自定义对象Student和其归属地NativePlace,并遍历。

package p02.SubClassDemo01.HashMapDemo;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map; class Student
{
private String name;
private int age;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Student() {
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
} class NativePlace
{
private String province;
private String city;
public NativePlace(String province, String city) {
super();
this.province = province;
this.city = city;
}
public NativePlace() {
super();
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
public class HashMapDemo { public static void main(String[] args) {
Demo01();
} private static void Demo01() {
HashMap<Student,NativePlace>hm=new HashMap<Student,NativePlace>();
hm.put(new Student("wangwu",25), new NativePlace("hubei","suizhou"));
hm.put(new Student("zhaoliu",26), new NativePlace("hunan","chagnsha"));
hm.put(new Student("zhangsan",23), new NativePlace("shandong","zibo"));
hm.put(new Student("lisi",24), new NativePlace("shandong","weifang")); //重复添加无效
hm.put(new Student("wangwu",25), new NativePlace("hubei","suizhou"));
hm.put(new Student("zhaoliu",26), new NativePlace("hunan","chagnsha"));
hm.put(new Student("zhangsan",23), new NativePlace("shandong","zibo"));
hm.put(new Student("lisi",24), new NativePlace("shandong","weifang")); for(Iterator<Map.Entry<Student,NativePlace>>it=hm.entrySet().iterator();it.hasNext();)
{
Map.Entry<Student, NativePlace>me=it.next();
Student stu=me.getKey();
NativePlace np=me.getValue();
System.out.println(stu.getName()+":"+np.getProvince()+"."+np.getCity());
} } }

2.TreeMap类。

TreeMap类底层使用了排序树,如果使用自定义对象作为键,就必须实现Comparable接口;如果没有实现这个接口,则必须使用比较器作为HashTree初始化对象的参数。

现在将上面的代码中Student的hashCode方法以及equals方法删掉,同时实现接口Comparable,重写compareTo方法,以达到按照年龄排序的目的。

package p02.SubClassDemo02.TreeMapDemo;

import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap; class Student implements Comparable<Student>
{
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Student() {
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Student o) {
int temp=this.age-o.getAge();
return temp==0?this.name.compareTo(o.getName()):temp;
}
} class NativePlace
{
private String province;
private String city;
public NativePlace(String province, String city) {
super();
this.province = province;
this.city = city;
}
public NativePlace() {
super();
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
} public class TreeMapDemo { public static void main(String[] args) {
Demo01();
} private static void Demo01() {
TreeMap<Student,NativePlace>hm=new TreeMap<Student,NativePlace>();
hm.put(new Student("wangwu",25), new NativePlace("hubei","suizhou"));
hm.put(new Student("zhaoliu",26), new NativePlace("hunan","chagnsha"));
hm.put(new Student("zhangsan",23), new NativePlace("shandong","zibo"));
hm.put(new Student("lisi",24), new NativePlace("shandong","weifang")); //重复添加无效
hm.put(new Student("wangwu",25), new NativePlace("hubei","suizhou"));
hm.put(new Student("zhaoliu",26), new NativePlace("hunan","chagnsha"));
hm.put(new Student("zhangsan",23), new NativePlace("shandong","zibo"));
hm.put(new Student("lisi",24), new NativePlace("shandong","weifang")); for(Iterator<Map.Entry<Student,NativePlace>>it=hm.entrySet().iterator();it.hasNext();)
{
Map.Entry<Student, NativePlace>me=it.next();
Student stu=me.getKey();
NativePlace np=me.getValue();
System.out.println(stu.getName()+":"+stu.getAge()+"----"+np.getProvince()+"."+np.getCity());
} } }

运行可以看出重复添加的元素仍然没有添加进去,因为TreeSet判断元素是否相同的依据是compareTo方法的返回值而不是hashCode方法以及equals方法。

如果现在有了新的需求,需要按照新的规则对学生进行排序,则创建比较器,按照比较器中的新规则进行排序。

package p02.SubClassDemo02.TreeMapDemo;

import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap; class Student implements Comparable<Student>
{
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Student() {
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Student o) {
int temp=this.age-o.getAge();
return temp==0?this.name.compareTo(o.getName()):temp;
}
} class NativePlace
{
private String province;
private String city;
public NativePlace(String province, String city) {
super();
this.province = province;
this.city = city;
}
public NativePlace() {
super();
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
} class CompareByName implements Comparator<Student>
{
@Override
public int compare(Student o1, Student o2) {
int temp=o1.getName().compareTo(o2.getName());
return temp==0?o1.getAge()-o2.getAge():temp;
}
}
public class TreeMapDemo {
public static void main(String[] args) {
Demo01();
} private static void Demo01() {
TreeMap<Student,NativePlace>hm=new TreeMap<Student,NativePlace>(new CompareByName());
hm.put(new Student("wangwu",25), new NativePlace("hubei","suizhou"));
hm.put(new Student("zhaoliu",26), new NativePlace("hunan","chagnsha"));
hm.put(new Student("zhangsan",23), new NativePlace("shandong","zibo"));
hm.put(new Student("lisi",24), new NativePlace("shandong","weifang")); //重复添加无效
hm.put(new Student("wangwu",25), new NativePlace("hubei","suizhou"));
hm.put(new Student("zhaoliu",26), new NativePlace("hunan","chagnsha"));
hm.put(new Student("zhangsan",23), new NativePlace("shandong","zibo"));
hm.put(new Student("lisi",24), new NativePlace("shandong","weifang")); for(Iterator<Map.Entry<Student,NativePlace>>it=hm.entrySet().iterator();it.hasNext();)
{
Map.Entry<Student, NativePlace>me=it.next();
Student stu=me.getKey();
NativePlace np=me.getValue();
System.out.println(stu.getName()+":"+stu.getAge()+"----"+np.getProvince()+"."+np.getCity());
} } }

可以看到,通过使用比较器,确实达到了按照名字字典序排序的目的,这也证明了如果使用比较器,则原来的自然比较方式将会无效。

3.LinkedHashMap类。

此类的是HashMap的子类,与HashMap相比,该类实现了“有序”,即插入和取出的顺序一致。该类在很多时候都能发挥出很大的作用。

java集合框架——Map的更多相关文章

  1. Java集合框架——Map接口

    第三阶段 JAVA常见对象的学习 集合框架--Map集合 在实际需求中,我们常常会遇到这样的问题,在诸多的数据中,通过其编号来寻找某一些信息,从而进行查看或者修改,例如通过学号查询学生信息.今天我们所 ...

  2. Java集合框架Map接口

    集合框架Map接口 Map接口: 键值对存储一组对象 key不能重复(唯一),value可以重复 常用具体实现类:HashMap.LinkedHashMap.TreeMap.Hashtable Has ...

  3. JAVA集合框架 - Map接口

    Map 接口大致说明(jdk11): 整体介绍: 一个将键映射到值的(key-value)对象, 键值(key)不能重复, 每个键值只能影射一个对象(一一对应). 这个接口取代了Dictionary类 ...

  4. java集合框架map

    Map<K,V> K key V value Map集合:该集合存储键值对.一对一对往里存,而且要保证键的唯一性. 1,添加. 2,删除. 3,判断. 4,获取. Map |--Hasht ...

  5. Java—集合框架Map

    Map接口 Map提供了一种映射关系,其中的元素是以键值对(key-value)的形式存储的,key和value可以是任意类型的对象,能够实现根据key快速查找value. Map中的键值对以Entr ...

  6. Java集合框架—Map

    Map集合:该集合存储键值对.一对一对往里存.而且要保证键的唯一性. 1,添加. put(K key, V value)  putAll(Map<? extends K,? extends V& ...

  7. Java集合框架List,Map,Set等全面介绍

    Java集合框架的基本接口/类层次结构: java.util.Collection [I]+--java.util.List [I]   +--java.util.ArrayList [C]   +- ...

  8. Java集合框架之map

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

  9. 【JAVA集合框架之Map】

    一.概述.1.Map是一种接口,在JAVA集合框架中是以一种非常重要的集合.2.Map一次添加一对元素,所以又称为“双列集合”(Collection一次添加一个元素,所以又称为“单列集合”)3.Map ...

随机推荐

  1. 江西财经大学第一届程序设计竞赛 B

    链接:https://www.nowcoder.com/acm/contest/115/B来源:牛客网 题目描述 给出一个出生日期,比如:1999-09-09, 问:从出生那一天开始起,到今天2018 ...

  2. 缓存算法及Redis、Memcached、Guava、Ehcache中的算法

    https://my.oschina.net/ffy/blog/501003 https://yq.aliyun.com/articles/622757 https://blog.csdn.net/s ...

  3. n阶乘,位数,log函数,斯特林公式

    一.log函数 头文件: #include <math.h> 使用: 引入#include<cmath> 以e为底:log(exp(n)) 以10为底:log10(n) 以m为 ...

  4. Java学习笔记day08_day09_对象实例化_private_this

    1.类与对象 类就是一个模版. 对象的实例化就是根据模版类, 使用new关键字创建实际的对象. 2.类的定义及创建对象 类的定义格式: public class 类名{ //属性(变量) 数据类型 变 ...

  5. Linux Vi/Vim 在插入模式下键盘右边数字键输入异常

    问题:Linux在 Vi/Vim 在编辑文件时遇到一个问题,当我在 Insert 模式下进行修改文件内容的时候,用到了键盘(104键,右边带数字键那种)进行数字输入,当我输入数字 “5” 时,插入的数 ...

  6. java——volatile的可见性不能保证线程安全

    volatile: 1.保证变量对所有线程的可见性(但是由于java里面的运算并非原子操作,导致volatile变量的运算在并发下一样是不安全的) 用代码试过,确实是这样的,原因:有可能同时多个thr ...

  7. java——数组操作

    排序.二分查找.复制数组.填充 package follow_pack; import java.util.Arrays; import java.text.DecimalFormat; public ...

  8. Git简单上传和下载

    本文参考 git-简易指南 编写 上传本地代码到gitHub仓库 第一步:建立git仓库 cd到你的本地项目根目录下,执行git命令 git init 第二步:将项目的所有文件添加到仓库中 git a ...

  9. prototype.js

    (1)$() 方法是在DOM中使用过于频繁的 document.getElementById() 方法的一个便利的简写, 就像这个DOM方法一样,这个方法返回参数传入的id的那个元素. (2)

  10. Maven 错误 Failure to transfer ...was cached in the local repository...

    Maven 错误 Failure to transfer ...was cached in the local repository... 我解决的时候多了两步才解决 1. mvn clean ins ...