Map集合学习
来源:互联网 发布:数据库如何打开mdf文件 编辑:程序博客网 时间:2024/06/08 03:45
Map集合学习
备注:Map:一次添加一对元素。Collection一次添加一个元素。
一、Map说明
Map也称为双列集合,Collection集合称为单列集合。
其实map集合中存储的就是键值对。
map集合中必须保证键的唯一性。
Map集合不具备迭代器。迭代器只有Collection系列的集合才有
二、Map接口的常用方法:
1,添加。
value put(key,value):返回前一个和key关联的值(上一个key对象的value值),如果没有返回null.
2,删除。
void clear():清空map集合。
value remove(key):根据指定的key翻出这个键值对。
3,判断。
boolean containsKey(key):
boolean containsValue(value):
boolean isEmpty();
4,获取。
value get(key):通过键获取值,如果没有该键返回null。当然可以通过返回null,来判断是否包含指定键。
int size(): 获取键值对的个数。
三、Map接口常用的实现类:
|--Hashtable :内部结构是哈希表,是同步的。不允许null作为键,不允许null作为值。
|--Properties:用来存储键值对型的配置文件的信息,可以和IO技术相结合。
|--HashMap : 内部结构是哈希表,不是同步的。允许null作为键,允许null作为值。
|--LinkHashMap:内部结构是哈希表和链接列表实现,具有可预知的迭代顺序(有序的)
|--TreeMap : 内部结构是二叉树,不是同步的。可以对Map集合中的键进行排序。
四、set集合和map集合关系
备注:
学习Set集合应该注意:Set集合的底层代码是由Map集合实现的。
为什么会有set集合?
因为:Map的集合中存储的是键值对,其中键在Map集合中是唯一的,因此将Map中的键作为set中的元素进行存储,就可以保证单列集合的唯一性了,这样就出现了没有重复元素的set集合了。
因为现实世界中因为有这样的需求,所以就有了set集合的存在
推论:
因为Set集合的底层代码是由Map集合实现的,所以set的子类xxxSet的底层实现是Map的子类xxxMap。
而我查看java的源码发现,这个推论在一定程度上是成立的。因为我发现:1)HashMap是HashSet的底层实现。2)TreeMap是TreeSet的底层实现。3)LinkedHashMap是LinkedHashSet的底层实现
1、HashMap是HashSet的底层实现
public HashSet() { map = new HashMap<>();}
2、TreeMap是TreeSet的底层实现
public TreeSet() { this(new TreeMap<E,Object>()); }
3、LinkedHashMap是LinkedHashSet的底层实现
public LinkedHashSet() { super(16, .75f, true); } HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); }
五、map遍历方法
1、方法一: Set<K> keySet()方法
取出map中的所有元素。
原理,通过keySet方法获取map中所有的键所在的Set集合,在通过Set的迭代器获取到每一个键,
在对每一个键通过map集合的get方法获取其对应的值即可。
思考:为什么是返回Set集合,而不是返回List集合呢?
map中的key是唯一的,而set集合有一个特点:元素是唯一的,所以返回set集合符合了map中key的特点,因此使用set集合。而List集合的元素则不保证集合元素的唯一性,所以没有考虑使用List集合。此处的选择,目的只有一个:确保拿到的key集合是唯一的,不重复的。
2、方法二: Set<Map.Entry<K,V>>entrySet()方法
通过Map转成set就可以迭代。
找到了另一个方法:entrySet。
该方法将键和值的映射关系作为对象存储到了Set集合中,而这个映射关系的类型就是Map.Entry类型
3、Map.Entry<K,V>之思
备注:内部类,内部接口需要进一步学习
(1)Map接口与Map.Entry接口
Map接口:外部接口(外部规则)
Map.Entry接口:内部接口(内部规则)--包含键和值的内容,是键和值的映射关系对象
(2)先后关系
先有Map接口中的Map(键值对)的映射,才有映射关系,而Entry接口做的就是把这个关系封装成了对象,且这个关系是访问Map中的键和值。
(3)外部规则与内部规则
外部规则里面有内部规则,内部规则可以直接访问内部规则的内部
(4)示例代码:
//内部接口:MyEntry 外部接口:MyMapinterface MyMap{ public static interface MyEntry{//内部接口 void get(); }} class MyDemoimplements MyMap.MyEntry{ public void get(){}}//内部类:Innnerclass Outer{ static class Inner{ static void show(){} }}
4、方法三:values方法
原理:取出Map集合中的所有值的Collection集合
5、三种方法的集合遍历案例
(1)代码实现
package map;/* * map集合遍历 * 1.遍历方法一:KeySet方法 * 2.遍历方法二:Map.Entry接口的 entrySet方法 * 3.遍历方法三:values方法 */importjava.util.Collection;importjava.util.HashMap;importjava.util.Iterator;importjava.util.Map;importjava.util.Map.Entry;importjava.util.Set;public class MapDemo { public static void main(String[] args) {// Map map=new HashMap(); Map<Integer,String> map=new HashMap<Integer,String>();//泛型 map.put(1, "张三"); map.put(2, "李四"); map.put(3, "王五"); map.put(4, "世间"); map.put(5, "时间"); //1.遍历方法一:KeySet方法 Set<Integer> keySet=map.keySet();//拿到键的集合 Iterator<Integer> it=keySet.iterator();//迭代器 System.out.println("遍历方法一:KeySet方法"); while(it.hasNext()){ int key=(int) it.next(); String value=map.get(key); System.out.println(key+":"+value); } //2.遍历方法二:Map.Entry接口的 entrySet方法 Set<Map.Entry<Integer,String>> bothResult=map.entrySet();//返回map集合中包含的键和值的映射关系 Iterator<Entry<Integer,String>>it2=bothResult.iterator();//迭代器 System.out.println("遍历方法二:Map.Entry接口的 entrySet方法"); while(it2.hasNext()){ Entry<Integer,String> entry=(Entry<Integer, String>) it2.next(); int key=entry.getKey(); String value=entry.getValue(); System.out.println(key+"::"+value); } //3.遍历方法三:values方法 Collection<String> cols=map.values(); Iterator<String> it3=cols.iterator(); System.out.println("遍历方法三:values方法"); while(it3.hasNext()){ String value=it3.next(); System.out.println(value); } }}
(2)结果
遍历方法一:KeySet方法
1:张三
2:李四
3:王五
4:世间
5:时间
遍历方法二:Map.Entry接口的 entrySet方法
1::张三
2::李四
3::王五
4::世间
5::时间
遍历方法三:values方法
张三
李四
王五
世间
时间
六、自定义对象存map集合,map集合保证键唯一性探讨
联系set集合
set集合中的TreeSet和HashSet中都有保证存入元素唯一的方法,而map集合如何保证存入map集合的键(key)唯一呢?
因为set集合的底层是通过map集合实现。
而且我们知道:
TreeMap是TreeSet的底层实现
HashMap是HashSet的底层实现
所以保证唯一,通过类比的方式得出:
HashMap(保证键唯一)与HashSet(保证元素唯一)方式一样
是通过对象的hashCode和equals方法来完成对象唯一性的。
TreeMap(保证键唯一)与TreeSet(保证元素唯一)方式一样
实现Comparable接口的compareTo方法 或者 实现 Comparator接口,覆盖compare方法
七、HashMap集合
1、HashMap集合说明
HashMap : 内部结构是哈希表,不是同步的。允许null作为键,允许null作为值。
2、HashMap集合保证键(key)唯一
HashMap是HashSet的底层实现
所以保证唯一,通过类比的方式得出:
HashMap(保证键唯一)与HashSet(保证元素唯一)方式一样
是通过对象的hashCode和equals方法来完成对象唯一性的。
3、自定义对象与非自定义对象之HashMap集合使用
(1)非自定义对象:
HashMap集合中存储非自定义对象,即:jdk中已有的对象(比如:String对象,Integer对象),这些对象覆盖了Object对象的hashCode方法和equals方法,可以保证这些对象插入HashMap集合时,键值是唯一的。
(2)自定义对象:
HashMap集合中存储自定义对象,即:自己写的对象。我们要想保证这样的自定义对象作为键时,键值是唯一的,我们需要给这个自定义对象覆盖Object对象的hashCode方法和equals方法。这样,才可以
可以保证这些自定义对象插入HashMap集合时,键值是唯一的。
4、HashMap案例
4.1案例一:将学生对象和学生的归属地通过键与值存储到map集合
(1)自定义对象Student类
class Student{ private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public int hashCode() { //乘以一些奇数,增大随机性 return this.name.hashCode()+age*37; } /* * 1.比较对象内容是否相同 * 2.健壮性判断(1)对象地址是否相同,相同则忽略比较(2)对象类型是否正确,错误则抛出异常 */ @Override public boolean equals(Object obj) { if(this==obj){ return true;//同一个学生 } if(!(obj instanceof Student)){ throw new RuntimeException("类型错误"); } //姓名和年龄都相同的视为同一个学生 Student s=(Student)obj; //同一个学生 if(this.getName().equals(s.getName())&&this.getAge()==s.getAge()){ return true; } return false;//不是同一个学生 } }
(2)HashMap测试类
package map; importjava.util.HashMap;importjava.util.Map;importjava.util.Set; import list_set.People; /* * 将学生对象和学生的归属地通过键与值存储到map集合中 * * 判断相同依据:姓名和年龄都相同的视为同一个学生 * * HashMap 类比 HashSet * 保证唯一:是通过对象的hashCode和equals方法来完成对象唯一性的 */public class HashMapDemo { public static void main(String[] args) { // HashMap hm=new HashMap<Student,String>(); HashMap<Student,String> hm=new HashMap<Student,String>(); hm.put(new Student("张三",20),"杭州"); hm.put(new Student("张三",20),"黑龙江");//和上面的键重复了,测试键是否插入唯一 //结果:只有一个new Student("张三",20)作为键,说明使用成功了 hm.put(new Student("李四",20),"广州"); hm.put(new Student("王五",20),"天津"); hm.put(new Student("李六",20),"北京"); hm.put(new Student("世间",20),"上海"); //遍历 Set<Map.Entry<Student,String>>set=hm.entrySet(); for(Map.Entry<Student, String> map:set){ Student s=map.getKey(); String name=s.getName();//名字 int age=s.getAge();//年龄 String area=map.getValue();//归属地 System.out.println(name+":"+age+":"+area); } } }
(3)结果:(保证了自定义对象的键唯一)
王五:20:天津
张三:20:黑龙江
世间:20:上海
李四:20:广州
李六:20:北京
4.2案例二:map对象存jdk已有对象
(1)测试类
package map;importjava.util.HashMap;importjava.util.Set;public class HashMapDemo2 { public static void main(String[] args) { HashMap<Integer,String> hm=new HashMap<Integer,String>(); hm.put(1, "张三"); hm.put(1, "张三");//重复键,覆盖原来的值 hm.put(2, "张三3"); hm.put(3, "张三5"); Set<Integer> set=hm.keySet(); for(Integer i:set){ int key=i; String value=hm.get(key); System.out.println(i+":"+value); } }}
(2)结果
Integer对象已经覆盖了Object对象的equals和hashCode方法,我们直接把Integer对象作为map集合的键插入集合中即可保证键的唯一性,无需自己做额外的操作
1:张三
2:张三3
3:张三5
八、TreeMap集合
1、TreeMap集合说明
TreeMap : 内部结构是二叉树,不是同步的。可以对Map集合中的键进行排序。
2、TreeMap集合保证键(key)唯一
TreeMap是TreeSet的底层实现
所以保证唯一,通过类比的方式得出:
TreeMap(保证键唯一)与TreeSet(保证元素唯一)方式一样
实现Comparable接口的compareTo方法 或者 实现 Comparator接口,覆盖compare方法
3、自定义对象与非自定义对象之TreeMap集合使用
(1)TreeMap集合排序方式一:让元素自身具备比较功能
【1】当元素为自定义对象(eg:Person类)时,让元素自身具备比较功能,实现Comparable接口,覆盖compareTo方法
【2】当元素为字符串对象(eg:“abd”)或者jdk中的对象有实现Comparable接口的方法时,由于这些对象本身已经实现了Comparable接口的compareTo方法,本身就具备比较功能,直接使用TreeMap即可。
(2)TreeMap集合排序方式二:让集合自身具备比较功能
让集合自身具备比较功能,定义一个类实现Comparator接口,覆盖compare方法。将该类对象作为参数传递给TreeMap集合的构造函数。
(3)排序优先
当TreeMap集合有两种比较功能时,TreeMap集合排序方式二(集合自身具备比较功能) 优先于 TreeMap集合排序方式一(元素本身具备比较功能)
4、TreeMap案例—按自定义对象的姓名属性排序
(1)实现方式一:
TreeMap集合排序方式一:让元素自身具备比较功能
【1】自定义对象XueSheng(实现Comparable接口)
package map; //学生对象public class XueSheng implements Comparable{ private String name; private int age; public XueSheng(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public int compareTo(Object o) { XueSheng s=(XueSheng)o; //按自定义对象的姓名属性排序 return this.getName().compareTo(s.getName()); } }
【2】TreeMap测试类
package map; importjava.util.Map;importjava.util.Set;importjava.util.TreeMap; /* * 将学生对象和学生的归属地通过键与值存储到map集合中 * * 按自定义对象的姓名属性排序 * TreeMap集合排序方式一:让元素自身具备比较功能 */public class TreeMapDemo { public static void main(String[] args) { TreeMap<XueSheng,String> tm=new TreeMap<XueSheng,String>(); tm.put(new XueSheng("张三",20),"杭州"); tm.put(new XueSheng("张三",20),"黑龙江");//和上面的键重复了,测试键是否插入唯一 //结果:只有一个new XueSheng("张三",20)作为键,说明使用成功了 tm.put(new XueSheng("李四",20),"广州"); tm.put(new XueSheng("王五",20),"天津"); tm.put(new XueSheng("李六",20),"北京"); tm.put(new XueSheng("世间",20),"上海"); //遍历 Set<Map.Entry<XueSheng,String>>set=tm.entrySet(); for(Map.Entry<XueSheng, String> map:set){ XueShengs=map.getKey(); String name=s.getName();//名字 int age=s.getAge();//年龄 String area=map.getValue();//归属地 System.out.println(name+":"+age+":"+area); } }}
【3】结果:(保证了自定义对象的键唯一)
世间:20:上海
张三:20:黑龙江
李六:20:北京
李四:20:广州
王五:20:天津
(2)实现方式二:
TreeMap集合排序方式二:让集合自身具备比较功能
【1】自定义对象XueSheng
package map; //学生对象public class XueSheng{ private String name; private int age; public XueSheng(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
【2】ComparatorByName比较器类
package map; importjava.util.Comparator;//比较器//实现 按自定义对象的姓名属性排序public class ComparatorByName implements Comparator{ @Override public int compare(Object o1, Object o2) { XueSheng s1=(XueSheng)o1; XueSheng s2=(XueSheng)o2; // 按自定义对象的姓名属性排序 return s1.getName().compareTo(s2.getName()); } }
【3】TreeMap测试类
package map; importjava.util.Map;importjava.util.Set;importjava.util.TreeMap; /* * 将学生对象和学生的归属地通过键与值存储到map集合中 * * 按自定义对象的姓名属性排序 * TreeMap集合排序方式二:让集合自身具备比较功能 */public class TreeMapDemo2 { public static void main(String[] args) { TreeMap<XueSheng,String> tm=new TreeMap<XueSheng,String>(new ComparatorByName()); //比较器的使用 tm.put(new XueSheng("张三",20),"杭州"); tm.put(new XueSheng("张三",20),"黑龙江2");//和上面的键重复了,测试键是否插入唯一 //结果:只有一个new XueSheng("张三",20)作为键,说明使用成功了 tm.put(new XueSheng("李四",20),"广州"); tm.put(new XueSheng("王五",20),"天津"); tm.put(new XueSheng("李六",20),"北京"); tm.put(new XueSheng("世间",20),"上海"); //遍历 Set<Map.Entry<XueSheng,String>>set=tm.entrySet(); for(Map.Entry<XueSheng, String> map:set){ XueSheng s=map.getKey(); String name=s.getName();//名字 int age=s.getAge();//年龄 String area=map.getValue();//归属地 System.out.println(name+":"+age+":"+area); } } }
【4】结果:
世间:20:上海
张三:20:黑龙江2
李六:20:北京
李四:20:广州
王五:20:天津
九、LinkedHashMap集合(有序)
LinkHashMap:【父类是HashMap】内部结构是哈希表和链接列表实现,具有可预知的迭代顺序(有序的)
联系set集合
LinkedHashSet的底层是由LinkedHashMap实现的。
说明:
如果要保证LinkedHashMap集合键的唯一性,可以参考父类HashMap的实现方式,它们俩实现是一样的。
案例
代码实现:
package map; importjava.util.Iterator;importjava.util.LinkedHashMap;importjava.util.Map;importjava.util.Map.Entry;/* * 有序 插入顺序和遍历获取顺序一致 */public class LinkedHashMapDemo { public static void main(String[] args) { LinkedHashMap<String,Integer> lhm=new LinkedHashMap<String,Integer>(); lhm.put("张三", 1023); lhm.put("lisi", 1021); lhm.put("王五", 1022); lhm.put("你好", 1025); lhm.put("世间", 1026); Iterator<Map.Entry<String,Integer>>it= lhm.entrySet().iterator(); while(it.hasNext()){ Entry<String,Integer> ele=it.next(); String key = ele.getKey(); Integer value = ele.getValue(); System.out.println(key+":"+value); } } }
结果:(有序)
张三:1023
lisi:1021
王五:1022
你好:1025
世间:1026
十、实现功能--记录字母次数
代码实现:
package map; importjava.util.Iterator;importjava.util.Map.Entry;importjava.util.TreeMap; /* * 记录字母次数 * * 字符串String s="kasdgasdvoasdfnasgsdgaegbweeegwef",获取该字符串中,每一个字母出现的次数。 * 要求打印结果是:a(5)b(1)...; * * 分析: * 1、记录结果包括字母和次数,确定容器为map集合,以键值对形式存储 * 2、因为输出结果是按照字母的字典顺序输出的,所以选择使用TreeMap集合 * 3、该实现特点:字母(key)不变,次数(value)不断变化 * 实现思路: * 1、key 是字母 value 是次数 * 2、将字符串转为字符数组,然后给字符数组进行遍历 * 3、遍历字符数组时,分两种情况考虑: * (1)当map集合中不存在当前字母(key),即把当前字母存入,并设置其value值为1【表示第一次出现】 * (2)当map集合存在当前字母(key),取出该字母对应的value,进行加1(value=value+1)操作【表示又一次出现】 * 4、进行遍历输出map集合中的key和value即可 */public class CountByCharacter { public static void main(String[] args) { String s="12kasdgasdv44oasdfnasgsdgaegbweeegwef"; char[] sArray=s.toCharArray();//字符串变字符数组 TreeMap<String,Integer> tm=arrayToMap(sArray);//计算字母出现次数,并将字母和次数保存在map集合中 listCount(tm);//遍历输出字符串中的字母和次数情况 } //计算字母出现次数,并将字母和次数保存在map集合中 private static TreeMap<String, Integer>arrayToMap(char[] sArray) { TreeMap<String,Integer> tm=new TreeMap<String,Integer>(); //遍历字符数组 for(int i=0;i<sArray.length;i++){ char letter=sArray[i]; //健壮性判断,key必须是字母,否则不进行存储和计算 boolean result=keyIsCharacter(letter); if(!result){ continue;//退出该次循环,直接进入下一次循环 } //键 String key=letter+"";//字符letter转为String类型 //默认情况设置为1(默认情况:key第一次出现) int value=1;//value=1 //key第二次出现 if(tm.get(key)!=null){ //value=value+1 value=tm.get(key)+1;//tm.get(key)就是上一个value值 } //key是char类型,需要转为String类型:key+"" tm.put(key, value);//设置key和value } return tm; } //判断key是否是字母,如果是,返回true;否则返回false private static boolean keyIsCharacter(char key) { //key是字母 if((key>='A'&&key<='Z')||(key>='a'&&key<='z')) return true; return false; } //遍历输出字符串中的字母和次数情况 private static void listCount(TreeMap<String, Integer> tm) { Iterator<Entry<String,Integer>>it=tm.entrySet().iterator(); while(it.hasNext()){ Entry<String,Integer> entry=it.next(); String key=entry.getKey(); int value=entry.getValue(); System.out.print(key+"("+value+") "); } }}
结果:
a(5) b(1) d(4)e(5) f(2) g(5) k(1) n(1) o(1) s(5) v(1) w(2)
结论:
不同容器有不同的应用场景,在不同情况下,有些容器实现起来极其简单和高效,所以我们要努力挖掘出该应用场景下的关键信息,然后做出最佳选择
- Map集合---学习例子
- Map集合学习笔记
- Map集合的学习
- 学习集合Collection , Map
- Map集合学习笔记
- Map集合视频学习
- java map集合学习
- Map集合学习
- Map集合学习笔记
- Map集合学习
- Java集合Map接口学习
- java Map 集合类学习
- Java集合Map接口学习
- Java 集合学习<6>map
- Java学习笔记-----集合Map
- java集合学习之Map
- java学习之Map集合
- 黑马程序员---Map集合 学习笔记
- 基于python实现的mmseg中文分词算法实现及其优化
- Java 9 Modularity Revealed.pdf 英文原版 免费下载
- python基础-11-迭代器生成器、模块和包
- Oracle之segmenthi高水平相关情况讨论??
- 张量代数的最最最基本应用
- Map集合学习
- Beginning Amazon Web Services with Node.js.pdf 英文原版 免费下载
- FTP服务
- 结合 TreeMap 源码分析红黑树在 java 中的实现
- C语言第八周作业+实验 总结报告 17/11/06
- Android 中的 IPC方式
- 33岁奇女子,INFP职业规划:我的原生家庭很悲剧,婚姻更不幸,还遇到了没良心的婆婆。
- Unity插件推荐
- PAT (Basic Level) Practise (中文)1027. 打印沙漏(20)