(十)Core Java 集合框架Map,Map扩展与TreeMap -03 (103)
目录 :
14 ).集合(map概述)
14 ).集合(map概述)
15 ).集合(Map子类对象特点)
16 ).集合(Map共性方法)
17 ).集合(Map-keySet)
18 ).集合(Map-entrySet)
19 ).集合(Map练习)
20 ).集合(TreeMap练习)
21).集合(TreeMap练习--字母出现的次数)
22 ).集合(Map扩展)
十四. 集合(map概述)
1 ) . 简述 :
1.1 Map与Collection一样都是顶级接口1.2 KPI简述 : 将键映射到值的对象;一个映射不能包含重复的键;每个键最多只能映射到一个值1.3 特点 :
[1] 该集合存储键值对,一对一往里存,而且要保证键的唯一性
2 ) . Map接口中的最共性的方法学习 :
2.1 增加
[1] put( K key,V value) --> 将指定的值与此映射中的指定键关联 -->也就是collection中的add一个性质[2] putAll(Map <? extedns K , ? extedns V> m)--> 从映射中将所有映射关系复制到此映射中
2.2 删除
[1] clear()--> 从映射中移除所有映射关系[2] remove(Object key)--> 从映射中移除指定的一个键的映射关系
2.3 判断
[1] containsValue(Object value)--> 此映射将一个或多个键映射到指定值 ,则返回true[2] containsKey(Object key)-->此映射包含键的映射关系,则返回true[3] isEmpty()--> 此映射未包含键值映射关系,则返回true
2.4 获取
[1] get(Object key)-->返回指定键所映射的值;若此映射不包含该键的映射关系,则返回null[2]size()-->返回此映射中的键值映射关系数[3] values()--> 返回此映射中包含的值的collection视图[4] entrySet () --> 返回此映射中包含的映射关系的set视图[5] keySet ( ) -->返回此映射中包含的键的set视图
3 ) . Map体系 : -->常用的实现类2.1 HashTable2.2 HashMap2.3 TreeMap
小结 :1. Collection中的泛型<>中存的是一个元素,而Map中的泛型<>中可存两个元素,因为是map是键值对类型,存在映射关系
十五. 集合(map子类对象特点)
1 ) . Map常用实现类 :
1.1 Hashtable --> 底层是哈希表数据结构,不可以存入null键null值,该集合是线程同步的, JDK1.0的 ; 效率低1.2 HashMap --> 底层是哈希表结构, 可以存入null键 null值. 该集合是线程不同步的,JDK1.2的,效率高 , 常用1.3 TreeMap --> 底层是二叉树数据结构,线程不同步,可以用于给map集合中的键进行排序
2 ) . 重点 : map和set很像, 事实上 set的底层调用的就是 map底层
2.1 剖析 : set存一个值, map同时存入两个值, 为了代码的简洁,两者共用一个方法是最妥当的 ,而共用一定是存元素多的那个
小结 :1. 往往元老级的一些集合都是线程同步的,例如 : vector , hashtable2. HashSet为何使用时,需要重写hashCode和equals呢? 因为 set底层调用的是map,而map是需要重写hashCode和equals的
十六. 集合(Map共性方法)
1 ) . Text :import java.util.*;/*Map常用实现类:HashTabale:底层是哈希表结构,键值都不允许为null,线程安全,jdk1.0 , 低效率HashMap:底层是哈希表结构,键值都允许为null,线程不安全,jdk1.2 ,高效率TreeMap: 底层是二叉树结构,可对集合中键进行排序ps:set集合底层调用的是map集合方法*/class MapDemo{public static void sop(Object obj){System.out.println(obj);}//主方法public static void main(String args[]){Map<String,String> mp= new HashMap<String,String>();//添加1//添加元素,若出现添加时,相同的键,那么后添加的值会覆盖原有对应值,并返回被覆盖的值sop( mp.put("01","summer") );sop( mp.put("01","aut") ); //同一键,覆盖summermp.put("02","autumn");mp.put("03","spring");mp.put("04","winter");//添加2//删除// mp.clear(); //清空映射中的所有映射//sop("remove:"+mp.remove("01")); -->删除01键对应的值,并返回删除的值//判断// sop("CcontainsKey:"+mp.containsKey("01")); -->通过键找值,找到的返回true//sop("containsValue:"+mp.containsValue("summer")); // -->通过值找值,找到则返回true// sop("isEmpty:"+mp.isEmpty()); // 判断映射中是否存在映射关系,当清空后则不存在//获取// sop("get:"+mp.get("01")); //-->获取01键对应的值,并返回获取的值// sop("size:"+mp.size()); //-->获取该集合中键值对的个数// sop("values:"+mp.values()); //-->获取该集合中所有值sop("keySet"+mp.keySet()); //-->获取该集合中所有键sop("entrySet"+mp.entrySet()); //返回映射关系的set映射图//小结 :删除,获取,若没有该值,则返回null//sop(mp);}}小结 :1. 接口,抽象类,是都不可以实例化的2. HashMap中也可以通过get的方式,来判断元素是否存在,因为get获取不到则会返回null3. collection中的add返回值是boolean类型,而Map中的put返回的值是当我们出现同一个键不同的值,添加了两次,第二次则会覆盖第一次加入的值并返回第一次的值
十七.集合(Map-ketSet)
1 ) . KeySet() -->就是用来获取map集合中所有的键的2 ) . 图解 :3 ) . Demo :import java.util.*;/*map集合的两种取出方式:1.keySet2.entrySet*/class KeySetDemo{public static void sop(Object obj){System.out.println(obj);}//主方法public static void main(String args[]){ //实例化HashMap对象Map<String,String> mp = new HashMap<String,String>();mp.put("01","summer");mp.put("02","spring");mp.put("03","autumn");mp.put("04","winter");//通过map集合中的方法keyset()来获取所有键,并把所有键放入set集合Set<String> keySet = mp.keySet();//set集合调用迭代器,打印所有keyfor(Iterator<String> it= keySet.iterator();it.hasNext();){String key=it.next();//有了key再通过map的get方法反向获取map集合中键所对应的值String value=mp.get(key);sop("key:"+key+"----value:"+value);}//获取所有键值对// sop(mp.entrySet());}}4 ) . 使用方式 :
4.1 用keySet()取值到set中,然后set调取iterator()方法迭代key元素,再通过map中的方法get(key)反向获取到value()值,完工
小结 :1. Collection集合中使用的是iterator迭代器迭代数据,Map集合中的keyset底层调用的是iterator迭代器,而后通过get获取键
十八. 集合(Map-EntrySet)
1 ) . Map-EntrySet -->这是一个用来描述关系的方法,同时Map.entry 又是 类型 , 形同结婚证
1.1 Map中的entrySet形同于collection中的迭代器,都是内部接口,定义在内部
2 ) . 定义内部类/内部接口的两个维度 :
2.1 一方面是先有(A)类,才能有(B)内部类时,两者的关系是先有A,才有有B时,那就定义内部类2.2 二方面是B必须得访问A类中的方法当两方面齐聚时,定义内部类是最优的解决方式
3 ) . 图解 :
4 ) . Demo :import java.util.*;/*map集合的两种取出方式:1.Set<k> keySet:1.1 方式[1]将map中所有的键存入到set集合,因为set具备迭代器[2]所以可以迭代方式取出所有的键,在根据get方法,获取每一个键对应的值1.2原理 :[1] Map集合的取出原理-->将map集合转成set集合,再通过迭代器取出2.entrySet:[1]Set<Map.Entry<K,V>>entrySet ; 讲map集合中的映射关系存入到set集合中,而这个关系的数据类型就是:Map.Entry*///内部接口实例//定义内部接口interface Map{public static interface Entry{public static Object getKet();public static Object getValue();}}// Map.Entry其实Entry也是一个接口,它是Map接口中的一个内部接口,看如下范例//定义 类,实现 接口interface HashMap implements Map{//定义内部类,实现内部接口class interior implements Map.Entry{public Object getKey(){}public Object getValue(){}}}class EntrySetDemo{public static void sop(Object obj){System.out.println(obj);}//主方法public static void main(String args[]){//实例化一个HashMap,键值对的泛型都为String类型Map<String,String> map = new HashMap();//存值map.put("01","summer");map.put("02","autumn");map.put("03","spring");map.put("04","winter");//调用关系类型entrySet()方法用将关系存储到Set集合中,--> Map.Entry:是作为类型的存在Set<Map.Entry<String,String>> st = map.entrySet();//set集合中的iterator迭代器方法用来将关系迭代出来for(Iterator<Map.Entry<String,String>> it = st.iterator(); it.hasNext();){//将关系再次存储到Map中,以好用键值对的方式取出Map.Entry<String,String> relation= it.next();//取键String key = relation.getKey();//取值String value = relation.getValue();//输出sop(key+"::"+value);}}}
5 ). 记住
5.1 map中的entrySet该方法是用来存储关系的,形同存储结婚证
小结 :1. Map.Entry用于表示映射关系的类型2. 只有内部类/内部接口的时候,才能定义为静态的3. 请记得,任何一个对象存到另一个集合中,存的都不是实体,实体在实例化的时候就已经确定位置了,集合中存储的都是引用/地址4. Map中的entrySet()用于存储关系,他的返回值类型是Map.Entry
十九. 集合(Map练习)
1 ) . 以下是Map中经典的两个方法 keySet与entrySet的使用方式2 ) . Demo :import java.util.*;/*需求:每个学生都有对应的归属地,学生Student,地址String学生属性:姓名,年龄注意:姓名和年龄相同的视为同一个学生,保证学生的唯一性步骤:1.描述学生2.定义Map容器,将学生作为键,地址作为值,存入3.获取map集合中的元素*/class Student implements Comparable<Student>{private String name;private int age;Student(String name,int age){this.name=name;this.age=age;}public void setName(String name){this.name=name;}public String getName(){return name;}public void setAge(int age){this.age=age;}public int getAge(){return age;}public String toString(){return name+":"+age;}//复写底层hashCode方法,为数据结构是哈希表的集合存储做提前准备public int hashCode(){return name.hashCode()+age*39;}//复写底层equals方法为底层数据结构是数组的集合做提前准备public boolean equals(Object obj){//判断传入的对象是否是student类型if(!(obj instanceof Student))throw new ClassCastException("类型转换异常");//Object向下转型,转为student类型Student st = (Student)obj;//名字相等并且年龄相等则返回truereturn this.name.equals(st.name) && this.age==st.age;}//复写底层compareTo方法为数据结构是二叉树的集合做准备public int compareTo(Student s){int num =new Integer(this.age).compareTo(new Integer(s.age));if(num==0)return this.name.compareTo(s.name);return num;}}class EntrySetText{public static void sop(Object obj){System.out.println(obj);}//主方法public static void main(String args[]){//实例化一个Map集合,并约束键值的泛型Map<Student,String> hm = new HashMap<Student,String>();hm.put(new Student("sunmmer",21),"beijing");hm.put(new Student("autumn",32),"wuhan");hm.put(new Student("winter",24),"changchun");hm.put(new Student("spring",18),"dongjing");//第一种方式取__>keySet//获取keySet方法,将键通过keySet()方法放入到set集合中Set<Student> keyset = hm.keySet();//调用迭代器,将键迭代出来for(Iterator<Student> it = keyset.iterator(); it.hasNext();){//获取键Student key = it.next();//若打印对象出现地址值的情况,那很有可能是toString出了问题//获取值String adr = hm.get(key);//输出键值System.out.println("key:"+key+"adr"+adr);}System.out.println( "-----------------------" );//第二种方式取__>EntrySet//通过entrySet将键值关系放入set集合中Set<Map.Entry<Student,String>> keyset1 = hm.entrySet();//将键值关系迭代出来for(Iterator<Map.Entry<Student,String>> ite = keyset1.iterator(); ite.hasNext();){//获取关系Map.Entry<Student,String> me = ite.next();//获取键Student key1 = me.getKey();//获取值String addr1 = me.getValue();//打印键值System.out.println(key1+"---"+addr1);}// 小结 :keySet() 与entrySet()方法的区别在于 前者用来迭代单个元素,后者用来迭代获取关系元素}}小结 :1. 用到hashSet或HashMap就要想到哈希表,就要想到哈希就要想到 hashCode () 与equals()让元素具备可比较性2. 用到treeSet , TreeMap就要想到二叉树,就要想到实现Comparable接口,重写compareTo()让元素具备可比较性3. 算数值尽量拿==比较,String类型的和对象类型的拿equals比较
二十. 集合(TreeMap练习)
1 ) . 我们可以通过内置元素排序,也可通过外置比较器进行排序2 ) . Text:import java.util.*;/*需求: 对学生对象的年龄进行升序排序因为数据是以键值对形式存在的,所以要使用可以排序的map集合TreemaptreeSet 与TreeMap 都可以排序*/class Student implements Comparable<Student>{private String name;private int age;Student(String name,int age){this.name=name;this.age=age;}public void setName(String name){this.name=name;}public String getName(){return name;}public void setAge(int age){this.age=age;}public int getAge(){return age;}public String toString(){return name+":"+age;}//复写底层hashCode方法,为数据结构是哈希表的集合存储做提前准备public int hashCode(){return name.hashCode()+age*39;}//复写底层equals方法为底层数据结构是数组的集合做提前准备public boolean equals(Object obj){//判断传入的对象是否是student类型if(!(obj instanceof Student))throw new ClassCastException("类型转换异常");//Object向下转型,转为student类型Student st = (Student)obj;//名字相等并且年龄相等则返回truereturn this.name.equals(st.name) && this.age==st.age;}//复写底层compareTo方法为数据结构是二叉树的集合做准备public int compareTo(Student s){int num =new Integer(this.age).compareTo(new Integer(s.age));if(num==0)return this.name.compareTo(s.name);return num;}}//外置比较器来排序class StuNameComparator implements Comparator<Student>{//按照名字排序public int compare(Student s1,Student s2){//若名字相等则按年龄排序int num = s1.getName().compareTo(s2.getName());if(num==0)return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));return num;}}class EntryTreeSetText{public static void sop(Object obj){System.out.println(obj);}//主方法public static void main(String args[]){TreeMap<Student,String> tm = new TreeMap<Student,String>();tm.put(new Student("summer",21),"nanjing");tm.put(new Student("winter",25),"beijing");tm.put(new Student("spring",27),"dongjing");tm.put(new Student("autumn",16),"xian");//entrySet 用在关系元素这里Set<Map.Entry<Student,String>> keySet = tm.entrySet();for(Iterator<Map.Entry<Student,String>> it = keySet.iterator(); it.hasNext();){Map.Entry<Student,String> me = it.next();Student s = me.getKey();String v = me.getValue();sop(s+":"+v);}}}小结 :1. treeMap,TreeSet 都涉及到外置比较器,切记实现方式是 实现Comparator接口,复写compare方法来改写比较方式
二十一. 集合(TreeMap练习--字母出现的次数)
1 ) . 需求 : 求字母在字符串中出现的次数import java.util.*;/*练习:"sdfgzcasdfxcvdf" 获取该字符串中的字母出现的次数打印结果 : a(1)c(2)....分析 : 通过结果发现,每个字母都有对应的次数,因此判定字母与次数之间存在映射关系注意 : 当存在映射关系时,可选择map集合,因为map集合中存放的就是映射关系什么时候使用map集合呢?当数据之间存在映射关系时,就要先考虑map集合思路 :1.将字符串转成字符数组,因为要对每一个字母进行操作2.定义一个map集合,因为打印结果的字母有顺序,所以使用treemap集合3.遍历字符数组[1] 通过将一个字母作为键去查map集合,若返回null,则该字母和1存入到map集合中;[2] 若返回不是null,则说明字母已在集合中存在并有对应次数,那么获取该次数并进行自增即可[3] 然后再将该字母和自增后的次数存入到map集合中,覆盖调用原键所对应的值4.将map集合中的数据变成指定的字符串形式返回*/class TreeMapText{public static void sop(Object obj){System.out.println(obj);}//抽取出一个计算字符个数的方法 --> 参数是字符串 , 返回值类型是字符串, 静态共享方法public static String charCount(String str){//先将字符串转为字符数组的形式 -->为了将字符串拆分为单个字符char[] ch = str.toCharArray();//实例化一个TreeMap,一来是因为字符与个数之间存在映射关系,二来是因为TreeMap具有默认排序功能,我们的键是字符,因此是Character,值是个数,因此是IntegerMap<Character,Integer> tm =new TreeMap<Character,Integer>();//声明一个变量,用来计数int count = 1;//迭代ch数组中的元素for(int i=0;i<ch.length;i++){//通过将数组中的元素通过get方法以键获取到值Integer value =tm.get(ch[i]);//判断是否有值,若不为空,则说明有值 , 则将值先付给count再++ ; 若为空,则说明无值,则直接++if(value ! = null )count = value; //将value赋给countcount++;//计数+1tm.put(ch[i],count); //将数组中的元素是键与count是值放入Treemap集合中count = 0;//清空计数}//初始化一个StringBuilder,用来存储可变的字符串变量StringBuilder sb = new StringBuilder();//通过map调取entrySet方法,这个方法用来将map的关系存到set中-->map.Entry是一种特殊的类型Set<Map.Entry<Character,Integer>> entrySet = tm.entrySet();//用来迭代关系 -->与往常不同的是,往常迭代的是一个一个,这次迭代的是一对一对for(Iterator<Map.Entry<Character,Integer>> it =entrySet.iterator();it.hasNext();){//将一对关系返回,用Map.entry类型接收Map.Entry<Character,Integer> me = it.next();//获取键Character k =me.getKey();//获取值Integer v =me.getValue();//将键值动态的添加到StringBuffer中 -->这里用stingBuffer就是因为它是字符串变量,能够多次修改而不产生新对象sb.append(k+"("+v+")");}//将StringBuffer接收的元素值返回return sb.toString();}//主方法public static void main(String args[]){//测试String sb = charCount("sdfgzcasdfaxcvdf");sop(sb);}}
小结 :1. 泛型内只能存引用基本类型,若要使用char时,应使用char的包装类作为类型
二十二. 集合(Map扩展)
1 ) . 需求 : 公司与部门与员工的关系分析 : 通过集合的形式实现import java.util.*;/*一个公司,内有5各部门,1一个部门3个员工*/class TreeMapText1{public static void sop(Object obj){System.out.println(obj);}/*//自定义在集合中设值的方式public static void text(){//创建一个HashMap的公司集合,内键是部门名,值是部门内员工HashMap<String,HashMap<String,String>> company = new HashMap<String,HashMap<String,String>>();//创建一个hashMap的宣传部集合,内键是员工编号,值是员工名字HashMap<String,String> publicity =new HashMap<String,String>();//创建一个HashMap的组织部集合,内键是员工编号,值是员工名字HashMap<String,String> organization =new HashMap<String,String>();//公司添加部门company.put("publicity",publicity);company.put("organization",organization);//宣传部添加员工publicity.put("001","summer");publicity.put("002","autumn");//组织部添加员工organization.put("003","winter");organization.put("004","spring");//遍历公司里的所有部门for(Iterator<String> it = company.keySet().iterator();it.hasNext();){ //返回公司所有部门名String department = it.next();//通过部门名获取到部门内所有员工的关系HashMap<String,String> depart = company.get(department);//用来迭代部门集合的getStaffInfo(depart);}}//自定义在集合中设值的方式//将相关部门键放入public static void getStaffInfo(HashMap<String,String> department){ //将所有关系放入set集合,因为set集合可以迭代Set<String> keyset = department.keySet();//通过迭代获取键值for(Iterator<String> it = keyset.iterator(); it.hasNext();){ //获取键String key = it.next();//通过键获取值String value =department.get(key);//输出键值sop(key+":"+value);}}*///-------------------------------------------------------------//自定义在集合中放对象的方式public static void demo(){//创建一个公司内有部门名,和部门实体HashMap<String,List<MyObject>> hm = new HashMap<String,List<MyObject>>();//创建两个部门List<MyObject> publicity =new ArrayList<MyObject>();List<MyObject> organization =new ArrayList<MyObject>();//公司添加部门hm.put("publicity",publicity);hm.put("organization",organization);//部门添加员工publicity.add(new MyObject("summer",18));publicity.add(new MyObject("autumn",15));organization.add(new MyObject("spring",21));organization.add(new MyObject("winter",24));//遍历公司里的所有部门for(Iterator<String> it = hm.keySet().iterator();it.hasNext();){ //返回公司所有部门名String department = it.next();//通过部门名获取到部门内所有员工的关系List<MyObject> depart = hm.get(department);//用来迭代部门集合的//将部门名放入这个可以迭代部门员工的方法内getMyObjectInfo(depart);}}//遍历部门内的员工的方法public static void getMyObjectInfo(List<MyObject> list)//传入部门{//迭代部门内员工for(Iterator<MyObject> it =list.iterator();it.hasNext();){//员工就是MyObjectMyObject myo= it.next();//输出员工信息sop("Name:"+myo.getName()+"............"+"Age:"+myo.getAge());}}//主方法public static void main(String args[]){demo();//text();}}//MyObject对象class MyObject{private String name;private int age;MyObject(String name,int age){this.name=name;this.age=age;}public void setName(){this.name=name;}public String getName(){return name;}public void setAge(){this.age=age;}public int getAge(){return age;}public String toString(){return "name:"+name+"age"+age;}}
小结 :1. 公司 --> 部门 --.>员工
[1] 公司对部门是 一对 多[2] 部门对员工是 一对多
2. 公司内查询员工 --> 迭代部门,迭代员工