一、Map集合
1、Map集合概述:
Map<K,V>集合是一个接口,和List集合及Set集合不同的是,它是双列集合,并且可以给对象加上名字,即键(Key)
1)Map特点:
a)该集合存储键值对,一对一对往里存
b)要保证键的唯一性。
2)Map体系
Map
|--Hashtable:底层是哈希表数据结构,是线程同步的。不可以存储null键,null值,效率低。
|--HashMap:底层是哈希表数据结构,是线程不同步的。可以存储null键,null值。替代了Hashtable,效率高。
|--TreeMap:底层是二叉树结构,可以对map集合中的键进行指定顺序的排序。
3)Map集合存储和Collection的区别:
Collection一次存一个元素;Map一次存一对元素。
Collection是单列集合;Map是双列集合。
Map中的存储的一对元素:一个是键,一个是值,键与值之间有对应(映射)关系。
特点:要保证map集合中键的唯一性。
2、Map集合共性方法
1)添加。
V put(K key,V value);//当存储的键相同时,新的值会替换老的值,并将老值返回。如果键没有重复,返回null。
void putAll(Map);//添加一个Map集合
2)删除。
void clear():清空
value remove(key) ;//删除指定键。
3)判断。
boolean isEmpty();//是否含有元素
boolean containsKey(key);//是否包含key
boolean containsValue(value) ;//是否包含value
4)取出。
int size();//返回长度
value get(key) ;//通过指定键获取对应的值。如果返回null,可以判断该键不存在。当然有特殊情况,就是在hashmap集合中,是可以存储null键null值的。
Collection values();//获取map集合中的所有的值。
3、Map集合的两种遍历方式
原理:Map中是没有迭代器的,而Collection具备迭代器,只要将Map集合转成Set集合,就可以使用迭代器了。之所以转成Set,是因为Map集合具备着键的唯一性,其实Set集合就来自于Map,Set集合底层其实用的就是Map的方法。
1)遍历Map集合方式一:Set keySet()方法。
可以将map集合中的键都取出存放到set集合中。对set集合进行迭代。迭代完成,再通过get方法对获取到的键进行值的获取。
2)遍历Map集合方式二:Set entrySet()方法,取的是键和值的映射关系。
Entry是Map接口中的内部接口,通过entrySet()方法把Map集合中的对应关系取出来,作为Map.Entry类型的元素存入Set集合中,由内部接口Map.Entry中的getKey()和getValue()方法可以分别获得对应关系的键和值。迭代Set集合中的对应关系,就可以获得Map集合的左右元素。
为什么要定义在map内部呢?entry是访问键值关系的入口,是map的入口,访问的是map中的键值对。
代码示例:
//通过两种方法遍历Map集合中的元素
import java.util.*;
class MapDemo {
publicstatic void main(String[] args) {
Map<String,String>map = new HashMap<String,String>();//定义一个HashMap集合
map.put("02","zhangsan2");//添加元素
map.put("03","zhangsan3");
map.put("01","zhangsan1");
map.put("04","zhangsan4");
//-----方式一-------
//先获取map集合的所有键的Set集合,keySet();
Set<String>keySet = map.keySet();
//有了Set集合。就可以获取其迭代器。
Iterator<String>it = keySet.iterator();
while(it.hasNext()){
Stringkey = it.next();
//有了键可以通过map集合的get方法获取其对应的值。
Stringvalue = map.get(key);
System.out.println("key:"+key+",value:"+value);
}
//-----方式一-------
//将Map集合中的映射关系取出。存入到Set集合中。
Set<Map.Entry<String,String>>entrySet = map.entrySet();
//获取迭代器
Iterator<Map.Entry<String,String>>it = entrySet.iterator();
while(it.hasNext()){
Map.Entry<String,String>me = it.next();
//通过getKey()方法获取键,getValue()方法获取值
Stringkey = me.getKey();
Stringvalue = me.getValue();
System.out.println(key+":"+value);
}
}
}
4、Map应用及扩展
a) 当量数据之间存在着映射关系的时候,我们就应该想到使用Map集合。
代码示例:
/*需求:获取一个字符串中各字母出现的次数。
希望打印结果:a(1)c(2).....
思路:
1将字符串转换成字符数组。因为要对每一个字母进行操作。
2定义一个map集合,因为打印结果的字母有顺序,所以使用treemap集合。
3,遍历字符数组。
将每一个字母作为键去查map集合。
如果返回null,将该字母和1存入到map集合中。
如果返回不是null,说明该字母在map集合已经存在并有对应次数。那么就获取该次数并进行自增。,然后将该字母和自增后的次数存入到map集合中。覆盖调用原理键所对应的值。
4,将map集合中的数据变成指定的字符串形式返回。
*/
import java.util.*;
class MapTest{
publicstatic void main(String[] args) {
Strings= charCount("ak+abAf1c,dCkaAbc-defa");
System.out.println(s);
}
publicstatic String charCount(String str){ //定义获取字符出现次数的方法
char[]chs = str.toCharArray(); //把字符串转成一个字符数组
TreeMap<Character,Integer>tm = new TreeMap<Character,Integer>();
int count = 0;//定义一个计数器
for(intx=0; x<chs.length; x++){
if(!(chs[x]>='a'&& chs[x]<='z' || chs[x]>='A' && chs[x]<='Z'))//判断是否为字母
continue;
Integervalue = tm.get(chs[x]);
if(value!=null)//判断Map集合中有没有这个字母
count= value;
count++;
tm.put(chs[x],count);
//直接往集合中存储字符和数字,为什么可以,因为自动装箱。
count= 0; //每次循环后计数器归零
}
StringBuilder sb = new StringBuilder();//定义一个容器来接受不定长的字符串
//遍历Map集合
Set<Map.Entry<Character,Integer>> entrySet =tm.entrySet();
Iterator<Map.Entry<Character,Integer>> it = entrySet.iterator();
while(it.hasNext()){
Map.Entry<Character,Integer>me = it.next();
Characterch = me.getKey();
Integervalue = me.getValue();
sb.append(ch+"("+value+")");
}
returnsb.toString();
}
}
b) 在很多项目中,应用比较多的是一对多的映射关系,这就可以通过嵌套的形式将多个映射定义到一个大的集合中,并将大的集合分级处理,形成一个体系。
代码示例:
/*
map扩展。
map集合被使用是因为具备映射关系。
以下是班级对应学生,而学生中学号对应着姓名的映射关系:
"yureban" Student("01""zhangsan");
"yureban" Student("02" "lisi");
"jiuyeban""01" "wangwu";
"jiuyeban""02" "zhaoliu";
就如同一个学校有多个教室。每一个教室都有名称。
*/
import java.util.*;
class MapExpandKnow{
publicstatic void main(String[] args) {
//预热班集合
HashMap<String,String>yureban=new HashMap<String,String>();
//就业班集合
HashMap<String,String>jiuyeban=new HashMap<String,String>();
//学校集合
HashMap<String,HashMap<String,String>>czbk=newHashMap<String,HashMap<String,String>>();
//学校中班级集合和名称的映射
czbk.put("yureban",yureban);
czbk.put("jiuyueban",jiuyeban);
//预热班级中学号与姓名的映射
yureban.put("01","zhangsan");
yureban.put("02","lisi");
//就业班级中学号与姓名的映射
jiuyeban.put("01","wangwu");
jiuyeban.put("02","zhouqi");
//直接显示全部学生信息
getAllStudentInfo(czbk);
}
//定义一个方法获取全部学生信息,包括在哪个班级,叫什么名字,学号多少
publicstatic void getAllStudentInfo(HashMap<String,HashMap<String,String>> hm){
for(Iterator<String> it=hm.keySet().iterator();it.hasNext() ; ) {//用keySet取出方式
Strings= it.next();//班级名称
System.out.println(s+":");
HashMap<String,String>stu=hm.get(s);//班级集合
getStudentInfo(stu);
}
}
//获取班级中学生的信息,包括姓名和学号
publicstatic void getStudentInfo(HashMap<String,String> hm){
for(Iterator<String> it=hm.keySet().iterator();it.hasNext() ; ){
Stringkey=it.next();//学号
Stringvalue=hm.get(key);//姓名
System.out.println(key+"..."+value);
}
}
}
5、使用集合的技巧:
1)看到Array就是数组结构,有角标,查询速度很快。
2)看到link就是链表结构:增删速度快,而且有特有方法。
3)看到hash就是哈希表,就要想要哈希值,就要想到唯一性,就要想到存入到该结构的中的元素必须覆盖hashCode,equals方法。
4)看到tree就是二叉树,就要想到排序,就想要用到比较。
比较的两种方式:
一个是Comparable:覆盖compareTo方法;
一个是Comparator:覆盖compare方法。
5)LinkedHashSet,LinkedHashMap:这两个集合可以保证哈希表有存入顺序和取出顺序一致,保证哈希表有序。
6)集合什么时候用?
当存储的是一个元素时,就用Collection。当存储对象之间存在着映射关系时,就使用Map集合。
要保证唯一,就用Set。不保证唯一,就用List。