一:Map接口介绍
Map接口提供了一种映射关系,其中的内容都是以键
key
值
value
对的形式存储的
public interface Map<K,V> {
}
K和V都是泛型 其中K指的是键的类型 V指的是值的类型
在初始化
Map
方法的时候需要指定这两个泛型
提醒
:不指定则默认为
Object
Map m1=new HashMap(); //键值都为Object类型
Map<String,String> m2=new HashMap<String,String>(); //键值都为String类型
- 键值对解释
从生活中的案例下手:国家简称
Japan(
日本
)
China(
中国
)
Germany(
德国
)
France(
法国
)
考虑到某些问题,于是对每个国家的名字进行了缩写
JP -- Japan(
日本
)
CN -- China(
中国
)
DE -- Germany(
德国
)
FR -- France(
法国
)
从案例中带入,突出
Map
键值对的以下特点
①
键与值相对应(互相绑定)
JP
对应的就是
Japan ,
这里将
JP
理解为键,那么对应的
Japan
就是值
②
键不能重复
对于世界而言,不会出现两个相同的国家简称
二:Map方法介绍
使用代码完成上方的国家简称案例
- 分析,得到键值的类型都为String,初始化Map集合
Map<String,String> ms=new HashMap<String,String>();
- 往集合中添加上面的案例数据 map.put(K,V)
ms.put("JP", "Japan");
ms.put("CN", "China");
ms.put("DE", "Germany");
ms.put("FR", "Franch");
讲解
put
方法:
往
Map
中添加键值对数据,并且是根据键来存放值,形成一对一的关系
存入时会碰到以下情况:
- 如果键在集合中不存在这个键,就是向集合中添加这个键值对
- 如果键在集合中已经存在了,就会用这个键值对替换原来的值
在以上案例新增代码
ms.put("JP", "hello");
System.out.println("添加之后的长度:"+ms.size());
输出结果:
添加之后的长度
:4
- 查看简称为 CN 的国家 map.get()
使用对应的键:
System.out.println("CN对应的国家:"+ms.get("CN"));
输出结果:
CN
对应的国家
:China
- 提出问题:如果被消灭了? map.remove()
需要在集合中移除对应的键
key :
ms.remove("JP");
System.out.println("移除之后的长度:"+ms.size());
输出结果:
ms.remove("JP");
System.out.println("移除之后的长度:"+ms.size());
- 查看当前集合中的元素,数据遍历操作
在
Map
集合中保存着两组值,一组用于保存
Map
的键
key
,另一组保存着
Map
的值
value
key
不能重复的原因:
使用的是
Set
集合
如果需要遍历数据,我们使用
map.keySet()
来获得所有的键
Set<String> ks = ms.keySet();
- 遍历ks,然后在根据key拿到对应的value:
输出结果:
提问:能不能直接拿到值?是不是也用一个
Set
集合装了所有的值?
for (String s : ks) {
// s是key
// 还需要调用get方法 拿到对应的value
System.out.println("键:"+s+"--值"+ms.get(s));
}
输出结果:
键
:DE--
值
Germany
键
:JP--
值
Japan
键
:CN--
值
China
键
:FR--
值
Franch
提问:能不能直接拿到值?是不是也用一个
Set
集合装了所有的值?
可以通过
values()
拿到所有的值,但不是
Set
集合,因为值是可以重复的
代码演示:
Collection<String> vs = ms.values();
for (String v : vs) {
System.out.println("值:"+v);
}
输出结果
:
值
:Germany
值
:Japan
值
:China
值
:Franch
- 使用 Entry 遍历
Map
中包括一个内部类
Entry,
该类封装一个键值对
interface Entry<K,V> {
Object getKey(); 返回该Entry里包含的key值;
Object getvalue(); 返回该Entry里包含的value值;
Object setValue(V value); 设置该Entry里包含的value值,并设置新的value值
}
代码演示:
Set<Entry<String, String>> es = ms.entrySet();
for (Entry<String, String> e : es) {
//e相当于一行数据 既包含key 也包含value
System.out.println("键:"+e.getKey()+"--值"+e.getValue());
}
输出结果:
键
:DE--
值
Germany
键
:JP--
值
Japan
键
:CN--
值
China
键
:FR--
值
Franch
三:Map接口下的实现类
- HashMapu与HashTable
哈希表(散列表)
哈希表结构解读请看下一篇博客
HashMap
和
Hashtable
的关系完全类似于
ArrayList
和
Vector
的关系
HashTable
是线性安全的,
HashMap
是线性不安全的,所以后者效率更高
HashTable
不允许使用
null
作为
key
和
value
,否则会引发异常,而
HashMap
可以
哈希表是数组
+
链表的结合体
jdk1.8
之后加入了红黑树结构
数组的特点是:寻址容易,插入和删除困难
而链表的特点是:寻址困难,插入和删除容易
举例:
手机上的通讯录,先根据姓氏分组(数组),每个姓氏对应一部分人(单向链表)
单向链表:
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
}
- TreeMap
TreeMap
是一个有序的
key-value
集合,它是通过红黑树实现的,每个
key-value
对即作
为红黑树的一个节点。能够把它保存的记录根据键排序,默认是按键值的升序排序(自然顺
序),也可以指定排序的比较器,不允许
key
值为空,非同步的。
四:Map应用案例
- 案例一(TreeMap)
1.
新建学生类:
public class Student {
private String name;
private int age;
}
2.
往
Map
中放入
5
个学生,
k=
学生对象,
v=
学生地址
TreeMap<Student, String> ms=new TreeMap<Student, String>();
ms.put(new Student("小黑", 18), "北京");
ms.put(new Student("小白", 22), "湖南");
ms.put(new Student("小青", 15), "杭州");
ms.put(new Student("小绿", 30), "西北");
ms.put(new Student("小黑", 18), "伦敦");
3.
集合长度
System . out . println ( " 集合的长度 :" + ms . size ());
输出结果
:
集合的长度
:5
分析原因:Set集合中判断元素是否重复
4.
提出修改要求:只要名字和年龄相同认为是同一个学生
提问:重写
equals
还是
hashCode?
两个都要重写,因为键是放在
Set
集合中(
Set
集合的判断规则是
hashCode+equals
结合)
@Override
public int hashCode() {
return this.name.hashCode()+this.age;
}
@Override
public boolean equals(Object obj) {
...
}
执行之前的代码,输出结果:
集合的长度
:4
5.
提出要求
:
输出所有的学生与对应的地址
Set<Entry<Student, String>> es = ms.entrySet();
for (Entry<Student, String> e : es) {
System.out.println(e);
}
输出结果
:
Person [name=
小绿
, age=30]=
西北
Person [name=
小青
, age=15]=
杭州
Person [name=
小黑
, age=18]=
北京
Person [name=
小白
, age=22]=
湖南
6.
提出要求:根据学生年龄大小来排序输出
使用自然排序,让学生类实现
Comparable
接口,重写比较方法:
@Override
public int compareTo(Student o) {
return this.age-o.age;
}
输出结果:
Person [name=
小青
, age=15]=
杭州
Person [name=
小黑
, age=18]=
北京
Person [name=
小白
, age=22]=
湖南
Person [name=
小绿
, age=30]=
西北
- 求字符串中字符的重复次数(HashMap)
1.
定义需要的
Map
集合
Map < String , Integer > ms = new HashMap < String , Integer > ();
2.
定义字符串
String str = "abca
3.
思路:
- 每次得到将字符串中的第一个字符 a ,并记录当前字符长度 a1
- 使用String的replace移除字符 a ,记录字符长度 a2
- a1 - a2 即可得出当前字符的个数
- 记录到map集合中
Map<String, Integer> ms=new HashMap<String, Integer>();
String str="abcdsdfhasfhjkehwkerggbgbmdfnbasnmfasdfklgasufweghuarbhasmfbs";
while(str.length()>0){//每次字符的长度会越来越短,如果为0就表示已经没有文字了
int a1=str.length();//未移除字符时的长度
String oldChar=str.charAt(0)+"";//得到当前字符串第一个字符
str=str.replace(oldChar, "");//从字符串中移除该字符
int a2=str.length();//移除狗的字符长度
ms.put(oldChar, a1-a2);//记录到map集合中
}
System.out.println(ms);
输出结果
:
{a=7, b=6, c=1, d=4, e=3, f=7, g=5, h=5, j=1,k=3, l=1, m=3, n=2, r=2, s=7, u=2, w=2}