在java中,除了Collection集合,还有一种集合叫做Map的集合。
Map也是一个接口,它的定义是:Map<K,V>,K,V是定义的泛型,K代表键,V代表值,Map的存放是以键值对的形式存放的,每一个键对应一个值,键就相当于数组的索引,只是键的类型是随意的,这也是Map集合最大的特点
在Map接口下有三个具体的实现:Hashtable,HashMap,TreeMap
Hashtable:底层数据类型是hash表(类似于HashSet),不能用null作为键或值,并且线程是同步的
HashMap:是Hashtable的升级版,区别在于HashMap可以用null作为键或值,线程是不同步的,其他与Hashtable一致
TreeMap:底层数据结构是二叉树,会对Map集合中的键进行排序,自定义排序方法类比TreeSet
==============================================================================================================================
Map中的方法:
1,添加:
V put(K key,V value)//若传入的参数key已被使用,那么value将覆盖原有的值,并且函数最终返回原有的值,否则函数返回null
putAll(Map<? extends K,? extends V>m)//添加一个集合
2,删除:
clear()//清空集合
V remove(K key)//删除键key及其值,返回其值,如果key不存在,返回null
3,判断:
containsValue(V value)//判断有没有该值
containsKey(K key)//判断有没有该键
isEmpty()//判断有没有内容
4,获取:
get(K key)//获取key对应的值,若不存在,返回null
size()//返回集合长度
Collection values()//Map集合中所有值存放到一个Collection集合中
entrySet方式获取//下面讲
keySet方式获取//下面讲
给个例子:
//实现录入学号
import java.util.*;
class MapDemo
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
Map<String,String> map=new HashMap<String,String>();
map.put("01","aaa");
map.put("02","bbb");
map.put("03","ccc");
map.put("04","ddd");
sop("02:"+map.containsKey("02"));
sop("eee:"+map.containsValue("eee"));
sop("01:"+map.get("01"));
map.remove("01");
sop("01:"+map.get("01"));
}
}
/*结果
02:true
eee:false
01:aaa
01:null
*/
=============================================================================================================================
由于Map集合没有调用迭代器的方法,因此要把Map集合的内容存到Set集合中,在利用Set集合的迭代器来获取Map集合中元素,keySet和entrySet就是这种原理
keySet方式获取值:
Set<K> s=map.keySet()//把Map集合中的所有键存入到一个Set集合中,再通过Set集合的迭代器获取内容(就是存入的键),再通过get函数获取值
修改上述例子:
import java.util.*;
class MapDemo
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
Map<String,String> map=new HashMap<String,String>();
map.put("01","aaa");
map.put("02","bbb");
map.put("03","ccc");
map.put("04","ddd");
Set<String> set=map.keySet();
Iterator<String> it=set.iterator();
while(it.hasNext())
{
String s=it.next();
sop(s+":"+map.get(s));
}
}
}
/*结果
04:ddd
01:aaa
02:bbb
03:ccc
因为底层是hash表,乱序是正常的
*/
entrySet方法获取值:
Set<Map.Entry<K,V>> s=map.entrySet()//把Map集合中的映射关系存放到Set集合中,说到这就要介绍一下Map.Entry<K,V>,这是一个Map内部静态接口,用来记录键值关系,并且该接口提供了两个重要的功能:
getKey()//获得该映射的键
getValue()//获得该映射的值
那么,把映射放入Set集合后,通过Set集合的迭代器再加上getKey,getValue方法获取内容
继续修改上述例子:
import java.util.*;
class MapDemo
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
Map<String,String> map=new HashMap<String,String>();
map.put("01","aaa");
map.put("02","bbb");
map.put("03","ccc");
map.put("04","ddd");
Set<Map.Entry<String,String>> set=map.entrySet();
Iterator<Map.Entry<String,String>> it=set.iterator();
while(it.hasNext())
{
Map.Entry<String,String> m=it.next();
sop(m.getKey()+":"+m.getValue());
}
}
}
/*结果
04:ddd
01:aaa
02:bbb
03:ccc
因为底层是hash表,乱序是正常的
*/
=============================================================================================================================
因为hashSet和hashtable底层是hash表,所以当用自定义类对象来当键时,由于键是唯一的,为了确保键的唯一性,需要在自定义类中要重写hashCode和equals方法,具体原理可参考hashSet集合
实例解释:
//需要建立一些学生对象,每个学生都对应着居住地,名字和年龄相同的为同一个学生
import java.util.*;
class Student
{
public int age;
public String name;
public Student(String name,int age)
{
this.age=age;
this.name=name;
}
public int hashCode()//根据名字年龄生成hash值
{
return name.hashCode()+age;
}
public boolean equals(Object s)
{
if(!(s instanceof Student))
throw new RuntimeException();
Student p=(Student)s;
if(this.age==p.age)
{
return this.name.equals(p.name);
}
return false;
}
}
class MapDemo
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
Map<Student,String> map=new HashMap<Student,String>();
map.put(new Student("zhangsan",12),"CHN");
map.put(new Student("zhangsan",12),"USA");
map.put(new Student("lisi",12),"USA");
map.put(new Student("zhangsan",15),"CHN");
Set<Map.Entry<Student,String>> set=map.entrySet();
Iterator<Map.Entry<Student,String>> it=set.iterator();
while(it.hasNext())
{
Map.Entry<Student,String> m=it.next();
Student s=m.getKey();
sop(s.name+"..."+s.age+":"+m.getValue());
}
}
}
/*结果
zhangsan...15:CHN
zhangsan...12:USA
lisi...12:USA
因为底层是hash表,乱序是正常的
之所以接收的12岁zhangsan来自USA是因为相同键的情况下后接收的值会覆盖先前的值
*/
同理,TreeMap在使用自定义类对象作为键时,也要自定义一个比较器或者自定义类实现Comparable,具体原理可参照TreeSet
对上述例子进行修改:
1,实现Comparable方式:
//需要建立一些学生对象,每个学生都对应着居住地,名字和年龄相同的为同一个学生
import java.util.*;
class Student implements Comparable<Student>//该接口使用了泛型,不明白就查阅API文档
{
public int age;
public String name;
public Student(String name,int age)
{
this.age=age;
this.name=name;
}
public int compareTo(Student s)
{
int num=this.age-s.age;
if(num==0)
{
return this.name.compareTo(s.name);
}
return num;
}
}
class MapDemo
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
Map<Student,String> map=new TreeMap<Student,String>();
map.put(new Student("zhangsan",12),"CHN");
map.put(new Student("zhangsan",12),"USA");
map.put(new Student("lisi",12),"USA");
map.put(new Student("zhangsan",15),"CHN");
Set<Map.Entry<Student,String>> set=map.entrySet();
Iterator<Map.Entry<Student,String>> it=set.iterator();
while(it.hasNext())
{
Map.Entry<Student,String> m=it.next();
Student s=m.getKey();
sop(s.name+"..."+s.age+":"+m.getValue());
}
}
}
/*结果
lisi...12:USA
zhangsan...12:USA
zhangsan...15:CHN
不仅正确接收内容(无重复),还根据自定义规则排序
*/
2,自定义比较器方式:
//需要建立一些学生对象,每个学生都对应着居住地,名字和年龄相同的为同一个学生
import java.util.*;
class MyComparator implements Comparator<Student>
{
public int compare(Student s1,Student s2)
{
int num=s1.age-s2.age;
if(num==0)
{
return s1.name.compareTo(s2.name);
}
return num;
}
}
class Student
{
public int age;
public String name;
public Student(String name,int age)
{
this.age=age;
this.name=name;
}
}
class MapDemo
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
Map<Student,String> map=new TreeMap<Student,String>(new MyComparator());//加入比较器
map.put(new Student("zhangsan",12),"CHN");
map.put(new Student("zhangsan",12),"USA");
map.put(new Student("lisi",12),"USA");
map.put(new Student("zhangsan",15),"CHN");
Set<Map.Entry<Student,String>> set=map.entrySet();
Iterator<Map.Entry<Student,String>> it=set.iterator();
while(it.hasNext())
{
Map.Entry<Student,String> m=it.next();
Student s=m.getKey();
sop(s.name+"..."+s.age+":"+m.getValue());
}
}
}
/*结果
lisi...12:USA
zhangsan...12:USA
zhangsan...15:CHN
效果完全一样
*/
=============================================================================================================================
最后讲一下多重映射关系,比如说在学校这个容器里,每个班都有自己的编号,而每个班又可以看做一个容器,其中的每个同学都有自己在班中的学号,这就出现了多重映射关系,在编程中就会出现容器中包含容器的情况
以上述例子说明:
import java.util.*;
class Student
{
public int age;
public String name;
public Student(String name,int age)
{
this.age=age;
this.name=name;
}
}
class MapDemo
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
Map<Integer,Map<String,Student>> school=new HashMap<Integer,Map<String,Student>>();//建立学校
Map<String,Student> classroom1=new HashMap<String,Student>();//建立教室
Map<String,Student> classroom2=new HashMap<String,Student>();
school.put(1,classroom1);//把教室加入学校容器,因为容器存的是对象的引用,所以先存教室再存学生和先存学生再存教室一样
school.put(2,classroom2);
classroom1.put("01",new Student("zhangsan",12));//把学生存入相应的教室
classroom1.put("02",new Student("lisi",15));
classroom1.put("03",new Student("wangwu",13));
classroom2.put("01",new Student("zhangsan",12));
classroom2.put("02",new Student("zhaoliu",12));
classroom2.put("03",new Student("lisi",17));
Set<Map.Entry<Integer,Map<String,Student>>> ss=school.entrySet();
Iterator<Map.Entry<Integer,Map<String,Student>>> s_it=ss.iterator();//用于遍历学校容器
while(s_it.hasNext())
{
Map.Entry<Integer,Map<String,Student>> m=s_it.next();
sop("classroom "+m.getKey()+":");
Set<Map.Entry<String,Student>> c=m.getValue().entrySet();
Iterator<Map.Entry<String,Student>> c_it=c.iterator();//用于遍历教室容器
while(c_it.hasNext())
{
Map.Entry<String,Student> c_m=c_it.next();
sop(c_m.getKey()+" : "+c_m.getValue().name+"..."+c_m.getValue().age);
}
}
}
}
/*结果
classroom 1:
01 : zhangsan...12
02 : lisi...15
03 : wangwu...13
classroom 2:
01 : zhangsan...12
02 : zhaoliu...12
03 : lisi...17
*/
用entrySet方法真是够酸爽!!!!