在现实生活中每个人都有唯一一个身份证号,通过身份证号可以查询到这个人的信息,这两者是一对一的关系。在应用程序中,如果想存储这种具有对应关系的数据,则需要使用JDK中提供的Map接口。Map接口时一个双列集合,它的每一个元素都包含一个键对象Key和一个值对象Value,键和值对象之间存在一种对应关系,称为映射。从Map集合中访问元素时,只要指定额Key就可以得到相应的Value。
Map集合中重要的几个接口和类如下:
①SortedMap接口:进一步提供关于键的总体排序 的 Map。该映射是根据其键的自然顺序进行排序的,或者根据通常在创建有序映射时提供的 Comparator 进行排序。
②NavigableMap接口:(SortedMap的子接口)扩展的 SortedMap,具有了针对给定搜索目标返回最接近匹配项的导航方法。
③AbstractMap抽象类:此类提供 Map 接口的骨干实现,以最大限度地减少实现此接口所需的工作。
④WeakHashMap类:(AbstractMap的子类)以弱键实现的基于哈希表的Map,即在WeakHashMap中,当某个键不再正藏使用的时,将自动移除其条目的键,其映射的存在并不阻止垃圾回收器对该键的丢弃。这就使得该键成为可终止的,被终止,然后被回收。
⑤ConcurrentMap类:(AbstractMap的子类)支持获取的完全并发和所期望可调整的并发的哈希表,是线程安全的。
⑥HashMap类:(AbstractMap的子类)提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是不保证该顺序恒久不变。
⑦TreeMap类:(AbstractMap的子类)基于红黑树(Red——Black Tree)的NavigableMap实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的ComparaTo进行排序,具体取决于使用的构造方法。
一、HashMap类相关的操作
(1)通过put(Object Key,Object Value)方法向集合中加入元素,通过get(Object Key)方法获取与键值对应的值;需要注意的是:键值必须是唯一的,不能重复。如果存储了相同的键,后面存储的值后覆盖掉原有的值,即键相同,值覆盖。
举例:
public void a() {
Map<String, Object> map = new HashMap<>();
map.put("1", "田田");
map.put("2", "蒸弦");
map.put("3", "无理");
map.put("3", "李尔");
System.out.println(map);
System.out.println(map.get("1"));//取出键1对应的值
System.out.println(map.get("2"));//取出键2对应的值
}
运行结果:
{1=田田, 2=蒸弦, 3=李尔}
田田
蒸弦
由结果可得:键值为“3”的重复了,后面的值“李尔”替换了原有的值“无理”
(2)遍历得到Map中所有的键值对
①第一种方法:首先调用Map对象的keySet()方法,获得存储Map中所有的键的Set集合,
然后通过Iterator迭代Set集合的每一个键,最后通过通过调用get(Object key)方法,
根据键获取对应的值。
public void b() {
Map<String, Object> map = new HashMap<>();
map.put("1", "田田");
map.put("2", "蒸弦");
map.put("3", "无理");
map.put("4", "李尔");
Set keySet = map.keySet();//获取键的集合
Iterator it = keySet.iterator();//迭代键的集合
while(it.hasNext()) {
Object key = it.next();
Object value = map.get(key);//获取每个键对应的值
System.out.println(key+":"+value);
}
}
运行结果:
1:田田
2:蒸弦
3:无理
4:李尔
②第二种方法:
首先调用Map对象的entrySet()方法获得存储在Map中所有映射的Set集合,这个集合中存放
了Map.Entry类型的元素(Entry是Map接口内部类),每个Map.Entry对象代表Map中的一个
键值对,然后迭代Set集合,获得每一个映射对象,并分别调用映射对象的getKey()和
getValue()方法获取键和值。
public void c() {
Map<String, Object> map = new HashMap<>();
map.put("1", "田田");
map.put("2", "蒸弦");
map.put("3", "无理");
map.put("4", "李尔");
Set enterySet = map.entrySet();
Iterator it = enterySet.iterator();
while(it.hasNext()) {
Map.Entry<String, Object> entry =(Map.Entry<String, Object>)(it.next());
Object key = entry.getKey();
Object vlaue = entry.getValue();
System.out.println(key+":"+vlaue);
}
}
运行结果:
1:田田
2:蒸弦
3:无理
4:李尔
二、TreeMap类的相关操作
(1)通过put(Object Key,Object Value)方法向集合中加入元素,通过get(Object Key)方法获取与键值对应的值;需要注意的是:键值必须是唯一的,不能重复。如果存储了相同的键,后面存储的值后覆盖掉原有的值,即键相同,值覆盖。除此之外,TreeMap集合,取出的元素是自动进行了排序的,是因为实现了Comparable接口,里面的comparaTo()方法会默认按照自然顺序进行排序。
例:
public void demo() {
Map<String, Object> map = new TreeMap<String, Object>();
map.put("3", "离儿");
map.put("1", "徐离");
map.put("2", "高键");
map.put("3", "菲菲");
System.out.println(map);
}
运行结果:
{1=徐离, 2=高键, 3=菲菲}
可以看到,结果是排了序的
(2)遍历得到Map中所有的键值对与HashMap方法相同
(3)对于自定义类的集合,需要实现Comparable接口并重写里面的comparaTo()方法,设定排序规则,如果不实现,会出现异常。
public void demo() {
Map<A,String > map = new TreeMap<>();
A a1 = new A(3, "lala", 20);
A a2 = new A(2,"yaya",30);
A a3 = new A(1, "lulu", 19);
map.put(a3,"露露");
map.put(a2,"丫丫");
map.put(a1,"啦啦");
System.out.println(map);
}
运行结果:
{A [id=1, name=lulu, age=19, getId()=]=露露,
A [id=2, name=yaya, age=30, getId()=]=丫丫,
A [id=3, name=lala, age=20, getId()=]=啦啦}
可以看到结果是按照id排序的
自定义类
public class A implements Comparable<A>{//实现Comparable接口
private Integer id;
private String name;
private Integer age;
public A(Integer id, String name, Integer age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public int hashCode() {
return id;
}
public String toString() {
return "A [id=" + id + ", name=" + name + ", age=" + age + ", getId()=]";
}
public boolean equals(Object obj) {
A a = (A)obj;
return this.getId()==a.getId();
}
public int compareTo(A o) {//重写compareTo()方法,按照id来排序
return this.getId()-o.getId();
}
}
三、有关HashMap、TreeMap键值是否可以为null的举例
public class Demo03 {
public void a() {
Map<Integer, Object> map1 = new HashMap<>();
String a1= "A2";
map1.put(559, "A1");
map1.put(471, a1);
map1.put(342, "A3");
map1.put(768, "A4");
map1.put(229, "A5");
map1.put(878, "A6");
System.out.println(map1);
System.out.println("----------------------------------");
map1.remove(342);
a1 = "AAA";
map1.put(648, null);
map1.put(null, null);
map1.put(null, "zhensghuang");
System.out.println(map1);
}
public static void main(String [] args){
new Demo01().a();
}
}
运行结果:
{768=A4, 229=A5, 342=A3, 471=A2, 878=A6, 559=A1}
---------------------------------------------------------------
{768=A4, null=zhensghuang, 229=A5, 471=A2, 648=null, 878=A6, 559=A1}
根据运行结果知:
HashMap的键为null和值为null都可以
(这里没有输出null=null,这对键值,是因为后面添加的键值null=zhengshuang,覆盖
了前面的null=null)
但是注意:TreeMap的j值可以为null,键能否为null分情况而言;
当没有实现Comparator接口时,TreeMap的键是不能为null的,会抛出java.lang.NullPointerException异常;
当实现Comparator接口时,并重写里面的compare()方法未对键为null进行判断,则抛出java.lang.NullPointerException异常
当实现Comparator接口时,并重写里面的compare()方法并对键为null进行判断,则可以成功存入
例如:下面是 键值为null时可以成功存入的情况
public void demo() {
Map<Integer, Object> map = new TreeMap<>(new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
if(o1 ==null) {
return 1;
}else {
return o2-o1;
}
}
});
map.put(2, null);
map.put(null, 2);
map.put(null,null);
System.out.println(map);
}
运行结果:
{2=null, null=2, null=null}
四、介绍有关集合的另外一种特殊情况:集合中存放的对象及对象内容发生改变,集合怎样变化
public void demo1() {
List<String> list = new ArrayList<>();
Set<String> set = new HashSet<>();
Map<Object,String> map = new HashMap<>();
String str = new String("abc");
list.add(str);
set.add(str);
map.put(6,str);
System.out.println(list);
System.out.println(set);
System.out.println(map);
System.out.println("---------------------");
str = new String("aaa");
System.out.println(list);
System.out.println(set);
System.out.println(map);
}
运行结果
[abc]
[abc]
{6=abc}
---------------------
[abc]
[abc]
{6=abc}
demo1()方法是对象的指向发生改变,由运行结果可知集合并未发生改变
public void demo2() {
List<A> list = new ArrayList<>();
Set<A> set = new HashSet<>();
Map<Integer,A> map = new HashMap<>();
A a = new A(1, "田菲", 20);
list.add(a);
set.add(a);
map.put(1, a);
System.out.println(list);
System.out.println(set);
System.out.println(map);
System.out.println("------------------------------");
a.setName("李盾");
System.out.println(list);
System.out.println(set);
System.out.println(map);
}
运行结果:
[A [id=1, name=田菲, age=20, getId()=]]
[A [id=1, name=田菲, age=20, getId()=]]
{1=A [id=1, name=田菲, age=20, getId()=]}
----------------------------------------------
[A [id=1, name=李盾, age=20, getId()=]]
[A [id=1, name=李盾, age=20, getId()=]]
{1=A [id=1, name=李盾, age=20, getId()=]}
demo2()方法存放的是对象的应用,可以看到对象的内容发生变化,集合也改变了
由两个方法对比可以总结出:
若是对象的指向发生改变,集合不改变;
若集合中存放的是对象的引用类型,如果对象的内容发生改变,对象的内存地址会发生改变,集合也就会改变。
两种情况结合的例子:
public void d() {
Map<Integer, A> map = new HashMap<>();
A a1 = new A(1, "张三", 29);
A a2 = new A(2,"田灿",20);
A a3 = new A(3,"旭样",44);
map.put(7, a1);
map.put(34, a2);
System.out.println(map);
a2.setName("田菲");//改变
System.out.println(map);
a2 = null;//这种方法并没有改变集合的内容,只是指向改变所以集合不改变
System.out.println(map);
a2 = a3;//不改变
System.out.println(map);
}
运行结果:
{34=A [id=2, name=田灿, age=20, getId()=], 7=A [id=1, name=张三, age=29, getId()=]}
{34=A [id=2, name=田菲, age=20, getId()=], 7=A [id=1, name=张三, age=29, getId()=]}
{34=A [id=2, name=田菲, age=20, getId()=], 7=A [id=1, name=张三, age=29, getId()=]}
{34=A [id=2, name=田菲, age=20, getId()=], 7=A [id=1, name=张三, age=29, getId()=]}
这里是A类的代码
public class A implements Comparable<A>{
private Integer id;
private String name;
private Integer age;
public A(Integer id, String name, Integer age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public int hashCode() {
return id;
}
@Override
public String toString() {
return "A [id=" + id + ", name=" + name + ", age=" + age + ", getId()=]";
}
public boolean equals(Object obj) {
A a = (A)obj;
return this.getId()==a.getId();
}
public int compareTo(A o) {
return this.getId()-o.getId();
}
}