Java基础-Map接口及其实现
来源:互联网 发布:深入java虚拟机 编辑:程序博客网 时间:2024/04/29 05:07
需求:有如下学生,学号和学生一一对应。
* 学号1 学生1
* 学号2 学生2
* 学号3 学生3
* 就我们目前所学的知识如何表达呢?
* 我们可以通过二维数组,或者一个Set和一个个List组合来表达。
* 但是,这样的话,我们就创建了多个容器。不好。
* 怎么办呢?java就提供了一种新的集合:Map
* Map:最大的优点就是体现对应关系。
* Map是一个键值对形式的集合。它的数据不再是单个的了,必须同时有键和值组成。
Map和Collection的区别:
Map:是(键值对)双列形式的集合;键必须是唯一的,不能重复,但其值(Value)可以重复
Collection:是单列值形式的集合;Collection体系中的List集合,元素允许重复;Set集合,元素不允许重复
还记得学习集合的原则——学顶层,用底层
那么现在来学习一下Map接口中的共性功能。
A:增加功能 V put(K key,V value):当key在集合中不存在时,添加元素;当key在集合存在时候,替换元素。代码:
import java.util.HashMap;import java.util.Map;public class Test12 { public static void main(String[] args) { //创建Map集合,由于Map是一个接口,只能通过new其子类HashMap来创建对象 Map<String,String> map = new HashMap<String,String>(); //创建并添加元素 put(key, value) map.put("01", "xiaocangyouzi"); map.put("02", "xiaozemaliya"); map.put("03", "mashengyoumei"); System.out.println("map : " +map); }}
结果:
分析:
这里的添加的方法与Collection体系中不一样,因为Map是以键值对存在的,所以要put两个内容,一个是key ,一个是value
B:删除功能 void clear():清除所有键值对数据。这个太暴力,一般不用。 V remove(Object key):根据指定的键删除键值对。 代码:
public class Test12 { public static void main(String[] args) { //创建Map集合,由于Map是一个接口,只能通过new其子类HashMap来创建对象 Map<String,String> map = new HashMap<String,String>(); //创建并添加元素 put(key, value) map.put("01", "xiaocangyouzi"); map.put("02", "xiaozemaliya"); map.put("03", "mashengyoumei"); //根据指定的key删除元素 remove(object key) map.remove("01"); System.out.println("remove key为01的元素后:" + map); //暴力清空 map.clear(); System.out.println("clear后的map: " + map); }}
结果:
分析:
remove是根据指定的key来删除元素,所以remove 01上的元素,集合里还有其他元素;而clear()是指清空整个集合
C:判断功能 boolean containsKey(Object key):判断指定的键是否在集合中存在 boolean containsValue(Object vlaue):判断指定的值是否在集合中存在 boolean isEmpty():判断集合是否为空 代码:
import java.util.HashMap;import java.util.Map;public class Test12 { public static void main(String[] args) { //创建Map集合,由于Map是一个接口,只能通过new其子类HashMap来创建对象 Map<String,String> map = new HashMap<String,String>(); //创建并添加元素 put(key, value) map.put("01", "xiaocangyouzi"); map.put("02", "xiaozemaliya"); map.put("03", "mashengyoumei"); //boolean containsKey(Object key):判断指定的键是否在集合中存在 System.out.println("map中包含01的key吗? " + map.containsKey("01")); //boolean containsValue(Object vlaue):判断指定的值是否在集合中存在 System.out.println("may中包含\"xiaocangyouzi\"的value吗? " + map.containsValue("xiaocangyouzi")); //boolean isEmpty():判断集合是否为空 System.out.println("这个集合为空吗? " + map.isEmpty()); }}
结果
获取长度功能:int size()代码
import java.util.HashMap;import java.util.Map;public class Test12 { public static void main(String[] args) { //创建Map集合,由于Map是一个接口,只能通过new其子类HashMap来创建对象 Map<String,String> map = new HashMap<String,String>(); //创建并添加元素 put(key, value) map.put("01", "xiaocangyouzi"); map.put("02", "xiaozemaliya"); map.put("03", "mashengyoumei"); //E:长度功能 int size() System.out.println("map集合的长度:" + map.size()); }}
结果:
在学习Collection体系的时候,我们对集合最常见的操作是遍历集合,获取集合中的值。那么我们如何遍历Map集合呢?
下面重点学习一下Map中的获取功能:
D:获取功能
Set
import java.util.Collection;import java.util.HashMap;import java.util.Map;import java.util.Set;public class Test12 { public static void main(String[] args) { //创建Map集合,由于Map是一个接口,只能通过new其子类HashMap来创建对象 Map<String,String> map = new HashMap<String,String>(); //创建并添加元素 put(key, value) map.put("01", "xiaocangyouzi"); map.put("02", "xiaozemaliya"); map.put("03", "mashengyoumei"); /*获取功能 * Object get(Object key):根据键获取值 * Set<K> keySet():所有键的集合 * Collection<V> values():所有值的集合 */ //获取所有键的集合 Set<String> keys = map.keySet(); System.out.println("map集合中所有key:"+keys); //获取所有value的集合 Collection<String> valuse = map.values(); System.out.println("map集合中所有value:" + valuse); //根据指定key获取value String value = map.get("01"); System.out.println("获取key为01的value:" + value); }}
结果:
分析:
为什么获取keySet的时候用的是Set集合,而获取values的时候,却使用Collection呢?
这是和map中的key和value的特性有关的~
在map中,key是不允许重复的,和set中不能存储重复元素的特性相关,所以选择set集合
而map中的value是允许重复的,假如还使用set集合来存储,那么就会冲问题,所以要使用
Collection体系中的List子体系存储。
通过学习上面的获取方法,我们是否可以通过上面获取到的key的集合keySet()还有get(Object key)来遍历Map集合呢?
我们知道,在Map体系中,key是唯一的,只要我们可以获取到key,那么就可以使用get(key)方法来获取所有元素。
那么下面来使用方式一来遍历Map中的元素
代码:
import java.util.HashMap;import java.util.Map;import java.util.Set;public class Test12 { public static void main(String[] args) { //创建Map集合,由于Map是一个接口,只能通过new其子类HashMap来创建对象 Map<String,String> map = new HashMap<String,String>(); //创建并添加元素 put(key, value) map.put("01", "xiaocangyouzi"); map.put("02", "xiaozemaliya"); map.put("03", "mashengyoumei"); //遍历方式一 //首先获取key的集合 Set<String> keys = map.keySet(); //通过遍历keys集合,每获取到一个key,就将该key对应的value输出 for(String key : keys) { String value = map.get(key); System.out.println(key +"--" + value); } }}
结果:
分析:
方式一的方法有三个步骤:
A:首先要先获取到map中的所有key,并且存储到一个set集合里面
B:要先获取每一个key对应的value,那么就需要将set集合里面的key一一获取到
C:每获取到一个key,就可以使用map的get(key)方法来获取对应的value
D:将key和对应的value打印出来
遍历Map集合还有第二种方法,刚才在map的获取功能里,我们还有一个功能没有学习,现在就可以用来遍历Map集合。
Set
import java.util.HashMap;import java.util.Map;import java.util.Set;public class Test12 { public static void main(String[] args) { // 创建Map集合,由于Map是一个接口,只能通过new其子类HashMap来创建对象 Map<String, String> map = new HashMap<String, String>(); // 创建并添加元素 put(key, value) map.put("01", "xiaocangyouzi"); map.put("02", "xiaozemaliya"); map.put("03", "mashengyoumei"); // 遍历方式二 // 先获取到Map.Entry<String,String>对象集合 Set<Map.Entry<String, String>> meSet = map.entrySet(); // 遍历meSet集合,获取到里面每一个Map.Entry<String,String>对象 for (Map.Entry<String, String> me : meSet) { //使用Map.Entry对象的getKey和getValue方法,分别回去值 String key = me.getKey(); String value = me.getValue(); //输出获取到的key和value System.out.println(key + "--" + value); } }}
结果:
分析:
使用Map.Entry键值对对象遍历Map集合步骤:
A:获取集合中所有的键值对,并封装成Map.Entry对象,存储在Set集合里面
B:遍历set集合,获取每一个Map.Entry对象
C:调用该对象的getKey获取key,调用该对象的getValue获取value
D:输出key和对应的value
Map接口中的自实现类HashMap
HashMap:基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null
键。(除了非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映
射的顺序,特别是它不保证该顺序恒久不变。
HashMap中的方法和Map中方法基本上保持一致,因此,我们学会了Map中的方法就可以了,这里就直接使用上面学习的一些方法,对HashMap集合进行操作:
需求: *HashMap存储键和值。并遍历。 键:String 值:String代码:
package cn.itcast_02;import java.util.HashMap;import java.util.Map;import java.util.Set;/* * HashMap存储键和值。并遍历。 * 键:String * 值:String */public class HashMapDemo { public static void main(String[] args) { // 创建集合对象 HashMap<String, String> hm = new HashMap<String, String>(); // 创建并添加元素 hm.put("刘备", "孙尚香"); hm.put("曹操", "卞氏"); hm.put("孙权", "步练氏"); // 遍历 Set<String> set = hm.keySet(); for (String key : set) { String value = hm.get(key); System.out.println(key + "***" + value); } System.out.println("---------------------"); // 遍历2 Set<Map.Entry<String, String>> hmSet = hm.entrySet(); for (Map.Entry<String, String> me : hmSet) { String key = me.getKey(); String value = me.getValue(); System.out.println(key + "***" + value); } }}
结果:
那么如果HashMap中的value为一个自定义对象,该如何操作呢?
HashMap存储键和值。并遍历。
键:String 学号
值:Student (name,age)
Student代码:
package cn.itcast_02;public class Student { private String name; private int age; public Student() { } 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() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; }}
HashMapDemo代码:
package cn.itcast_02;import java.util.HashMap;import java.util.Map;import java.util.Set;/* * HashMap存储键和值。并遍历。 * 键:String 学号 * 值:Student (name,age) */public class HashMapDemo2 { public static void main(String[] args) { // 创建集合对象 HashMap<String, Student> hm = new HashMap<String, Student>(); // 创建元素对象 Student s1 = new Student("李世民", 30); Student s2 = new Student("朱元璋", 40); Student s3 = new Student("武则天", 50); // 添加元素 hm.put("it001", s1); hm.put("it002", s2); hm.put("it003", s3); // 遍历 Set<String> set = hm.keySet(); for (String key : set) { Student value = hm.get(key); System.out.println(key + "***" + value.getName() + "***" + value.getAge()); } // 遍历2 Set<Map.Entry<String, Student>> hmSet = hm.entrySet(); for (Map.Entry<String, Student> me : hmSet) { String key = me.getKey(); Student value = me.getValue(); System.out.println(key + "***" + value.getName() + "***" + value.getAge()); } }}
结果:
上面的案例的数据都是正常的数据,如果现在,我们往集合中加入一些相同key,但是不同内容的元素时,是否可以保证key的唯一呢?
测试代码:
package cn.itcast_02;import java.util.HashMap;import java.util.Map;import java.util.Set;/* * HashMap存储键和值。并遍历。 * 键:String 学号 * 值:Student (name,age) */public class HashMapDemo2 { public static void main(String[] args) { // 创建集合对象 HashMap<String, Student> hm = new HashMap<String, Student>(); // 创建元素对象 Student s1 = new Student("李世民", 30); Student s2 = new Student("朱元璋", 40); Student s3 = new Student("武则天", 50); Student s4 = new Student("大傻逼", 50); // 添加元素 hm.put("it001", s1); hm.put("it002", s2); hm.put("it003", s3); hm.put("it003", s4); // 遍历 Set<String> set = hm.keySet(); for (String key : set) { Student value = hm.get(key); System.out.println(key + "***" + value.getName() + "***" + value.getAge()); } System.out.println("------华丽的分割线------"); // 遍历2 Set<Map.Entry<String, Student>> hmSet = hm.entrySet(); for (Map.Entry<String, Student> me : hmSet) { String key = me.getKey(); Student value = me.getValue(); System.out.println(key + "***" + value.getName() + "***" + value.getAge()); } }}
结果:
分析:
这里被替换掉了。。。说明在HashMap中,key是唯一的,当集合中存在一个已有的key,再
往里添加的相同key的元素时,新的元素会替换掉旧的元素。
为什么String类型的数据可以做到保证唯一呢?
我们可以看一下String类的源码。在之前的学习中,我们知道,在hash数据结构中,要想保证唯一性,就
必须重写hashCode方法和equals方法
String类重写hashCode方法
String类重写equals方法
那么,如果我们需要使用自定义对象作为HashMap中的key的时候,也应该在该对象所属的类中,重写hashCode方法和equals方法:
改进代码如下:
Student.java
package cn.itcast_02;public class Student { private String name; private int age; public Student() { } 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() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; }}
HashMapDemo.java
package cn.itcast_02;import java.util.HashMap;import java.util.Set;/* * HashMap存储键和值。并遍历。 * 键:Student (name,age) * 值:String 学号 * * 特有需求:两个对象的成员变量值如果都相同。我们则认为是同一个对象。 */public class HashMapDemo3 { public static void main(String[] args) { // 创建集合对象 HashMap<Student, String> hm = new HashMap<Student, String>(); // 创建元素对象 Student s1 = new Student("李世民", 30); Student s2 = new Student("朱元璋", 40); Student s3 = new Student("武则天", 50); Student s4 = new Student("武则天", 50); Student s5 = new Student("武则天", 30); // 添加元素 hm.put(s1, "it001"); hm.put(s2, "it002"); hm.put(s3, "it003"); hm.put(s4, "it004"); hm.put(s5, "it005"); // 遍历 Set<Student> set = hm.keySet(); for (Student key : set) { String value = hm.get(key); System.out.println(key.getName() + "***" + key.getAge() + "***" + value); } }}
结果:
分析:
在代码中,添加了两个我们认为是相同的对象,但是由于在Student类中重写了hashCode和equals方法,所以在HashMap中添加的时候,就没有加入成功。这样就保证了key的唯一性
TreeMap:
TreeMap和HashMap的底层数据结构不同,TreeMap底层的数据结构是红黑树。它保证了元素存储时候按
一定的规则(自然顺序或者自定顺序)存储,并且保证了元素的唯一。
那么TreeMap是通过什么方法保证元素的唯一和顺序的呢?
在学习TreeSet中我们知道,这里有两种方式可以实现,那么TreeMap也是通过这两种方式实现的:
A:对对象所属的类实现Comparable接口,并且重写compareTo方法。
B:调用TreeMap的带参构造方法,并且在参数位置,传入Comparator接口的子类对象,重写
compare方法
在开发中,我们一般会选择第二种方式。遵循一个原则:对修改关闭,对扩展开放。
那么,与上面的HashMap一样,在TreeMap存放String类型的key时,是可以保证唯一和顺序的。因为String类都重写了这些方法和实现了这些接口。
那么我们主要来测试在TreeMap中存放自定义类型数据作为key的情况;
代码:
Student.java
package cn.itcast_03;public class Student { private String name; private int age; public Student() { } 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; }}
TreeMapDemo.java
package cn.itcast_03;import java.util.Comparator;import java.util.Set;import java.util.TreeMap;import cn.itcast_02.Student;/* * TreeMap存储自定义对象并遍历。 * 键:Student * 值:String * * 如果一个自定义对象做键,用TreeMap集合。 * 就必须要实现排序。 * 两种方式: * A:让自定义对象所属的类去实现Comparable接口 * B:使用带参构造方法,创建TreeMap,接收Comparator接口参数。 */public class TreeMapDemo2 { public static void main(String[] args) { // 创建集合对象 TreeMap<Student, String> tm = new TreeMap<Student, String>( new Comparator<Student>() { @Override public int compare(Student s1, Student s2) { // int num = s1.getAge() - s2.getAge(); int num = s2.getAge() - s1.getAge(); int num2 = (num == 0) ? s1.getName().compareTo( s2.getName()) : num; return num2; } }); // 创建元素对象 Student s1 = new Student("李世民", 30); Student s2 = new Student("朱元璋", 40); Student s3 = new Student("武则天", 50); Student s4 = new Student("武则天", 50); Student s5 = new Student("武则天", 30); // 添加元素 tm.put(s1, "it001"); tm.put(s2, "it002"); tm.put(s3, "it003"); tm.put(s4, "it004"); tm.put(s5, "it005"); // 遍历 Set<Student> set = tm.keySet(); for (Student key : set) { String value = tm.get(key); System.out.println(key.getName() + "***" + key.getAge() + "***" + value); } }}
结果:
分析:
从结果可以看出,有两个相同的对象,后面添加的将前面的覆盖了,也是保证了key的唯一。
另外,我们可以看到是按照年龄的从大到小排序的。
Hashtable和HashMap的区别:
特别注意:
由于历史遗留问题,Hashtable的命名不符合我们现在的规范,但是Hashtable在JDK1.0的时候就出现,
目前还有很多程序时使用该类,所以就没有将名称修改,我们一定要注意。
Hashtable :线程安全,效率低;不允许null 的键和值
HashMap :线程不安全,效率高;允许null的键和值
代码:
package cn.itcast_04;import java.util.HashMap;/* * Hashtable和HashMap的区别? * A:Hashtable线程安全,效率低;不允许null键和值。 * B:HashMap线程不安全,效率高;允许null键和值。 */public class HashtableDemo { public static void main(String[] args) { HashMap<String, String> hm = new HashMap<String, String>(); hm.put("hello", null); hm.put(null, "world"); hm.put(null, null); System.out.println(hm); }}
结果:
分析:
这里没有报错,说明在HashMap中是允许null的键和值的。
为什么只有两个元素呢?因为,有两个key为null,所以后者将前者替换掉了
Hashtable
package cn.itcast_04;import java.util.Hashtable;/* * Hashtable和HashMap的区别? * A:Hashtable线程安全,效率低;不允许null键和值。 * B:HashMap线程不安全,效率高;允许null键和值。 */public class HashtableDemo { public static void main(String[] args) { Hashtable<String, String> ht = new Hashtable<String, String>(); ht.put("hello", null); ht.put(null, "world"); ht.put(null, null); System.out.println(ht); }}
结果:
分析:
NullPointerException 空指针异常。
- Java基础-Map接口及其实现
- java SE基础(Map接口及其实现)
- java之Map接口及其实现类
- 黑马程序员 Java基础——Map接口及其实现类
- Map接口及其实现类
- Java基础---集合(Set接口及其子类、Map接口及其子类)
- Java基础之Iterator、Map、Map.Entry接口,及其综合利用之Map遍历
- java--17--Map及其实现类与子接口
- 【Java学习笔记】34:Map接口及其实现类
- List接口及其实现类、Map接口及其实现类
- Java基础复习:Map接口
- java Map及其实现类
- Java容器学习笔记(三) Map接口及其重要实现类学习总结
- Java学习笔记(三)Map接口及其重要实现类的用法
- Java双例集合下Map接口及其常用实现类
- JavaSE入门学习37:Java集合框架之Map接口及其实现类HashMap和TreeMap
- 八,Java集合类(6)——Map接口及其实现类
- java--运用Map接口及其实现类完成简易学生系统的管理
- OpenCV学习笔记(0)—— 摄像机模型与标定1
- iOS开发概述 - 14.CALayer隐式动画
- CSS学习笔记----(三)
- Eclipse下Android项目结构介绍
- 学习MongoDB--(1):MongoDB简介
- Java基础-Map接口及其实现
- 求分数--推荐指数(★★★★★)
- 20150805训练题
- 黑马程序员 oc随记 类方法与对象方法
- poj 1379
- c语言中 switch case 和 if else执行效率的比较
- Java学习——话说J2EE发展历程
- (一一二)图文混排中特殊文字的点击与事件处理
- 问题请教