HashMap四种常见的键的类型:
HashMap<String,String>、HashMap<Integer,String>、HashMap<String,Student>、HashMap<Student,String>(其中的Student只是我们自定义的一个学生类)
例如:
package com.westos.HashMap; import java.util.HashMap; import java.util.Set; /** *HashMap(String (学号),String(姓名))形式 */ public class HashMapDome { public static void main(String[] args) { //创建HashMap集合的对象 HashMap<String,String> map=new HashMap<String,String>(); map.put("132614", "曹乾"); map.put("132118", "刘崇华"); map.put("132194", "马玉超"); map.put("132668", "宋晓波"); map.put("132668", "于金乐"); map.put("132614", "井杰"); //收集集合中所有的键对象 Set<String> key = map.keySet(); //增强for循环 for(String str:key) { //获取所有与键对应的值 String value = map.get(str); System.out.println(str+"----"+value); } } } 运行结果: 132614----井杰 132118----刘崇华 132668----于金乐 132194----马玉超
例如:
package com.westos.HashMap; import java.util.HashMap; import java.util.Set; /** *HashMap<Integer(年龄),String(姓名)>形式 * */ public class HashMapDome2 { public static void main(String[] args) { //创建HashMap集合的对象 HashMap<Integer,String> map=new HashMap<Integer,String>(); //添加集合中的元素 map.put(25, "Angelababy"); map.put(23, "吴宣仪"); map.put(24, "赵星星"); map.put(22, "孟美岐"); map.put(25, "迪丽热巴"); //获取集合中所有的键 Set<Integer> keySet = map.keySet(); //增强for循环 for(Integer key:keySet) { String value = map.get(key); //遍历出每一个键和它对应的值 System.out.println(key+"----"+value); } } } 运行结果: 22----孟美岐 23----吴宣仪 24----赵星星 25----迪丽热巴
package com.westos.HashMap; public class Student { private String name; private int age; public Student() { super(); } public Student(String name, int age) { super(); 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; } }
package com.westos.HashMap; /** * HhashMap<String(学号),Student(学生的姓名和年龄) */ import java.util.HashMap; import java.util.Set; public class HashMapDome3 { public static void main(String[] args) { //创建HashMap集合对象 HashMap<String,Student> map=new HashMap<String,Student>(); //创建学生对象 Student s1=new Student("迪丽热巴",25); Student s2=new Student("吴宣仪",23); Student s3=new Student("孟美岐",23); Student s4=new Student("赵星星",24); Student s5=new Student("迪丽热巴",25); //将学生对象添加进集合中去 map.put("001", s1); map.put("002", s2); map.put("003", s3); map.put("004", s4); map.put("005", s5); //获取集合中所有的键 Set<String> set = map.keySet(); //增强for循环 for(String key:set) { Student value = map.get(key); System.out.println(key+":"+value.getName()+"----"+value.getAge()); } } } 运行结果: 001:迪丽热巴----25 002:吴宣仪----23 003:孟美岐----23 004:赵星星----24 005:迪丽热巴----25
例如:
学生类就用了上面的那个学生类
package com.westos.HashMap; /** * HashMap<Student,String>类型 */ import java.util.HashMap; import java.util.Set; public class HashMapDome4 { public static void main(String[] args) { //创建HashMap集合对象 HashMap<Student,String> map=new HashMap<Student,String>(); //创建学生对象 Student s1=new Student("迪丽热巴",25); Student s2=new Student("吴宣仪",23); Student s3=new Student("孟美岐",23); Student s4=new Student("赵星星",24); Student s5=new Student("迪丽热巴",25); //将学生对象添加进集合中去 map.put( s1,"001"); map.put( s2,"002"); map.put( s3,"003"); map.put( s4,"004"); map.put( s5,"005"); //获取集合中所有的键 Set<Student> set = map.keySet(); //for循环 for(Student key:set) { String value = map.get(key); System.out.println(key.getName()+"="+key.getAge()+"--"+value); } } } 运行结果: 赵星星=24--004 吴宣仪=23--002 迪丽热巴=25--005 孟美岐=23--003
从最后的这个HashMap<Student,String>类型中当我们的键(就是学生类的对象)内容一样时,运行结果中后面的那个一样的键的值替代了前面的那个键的值,要想达到这种去重的效果,必须在自定义类中添加重写方法(equals方法和HashCode方法),因为我们是自定义类,调用自定义对象时,在底层代码中系统并没有帮我们重写这两个方法,所以必须我们自己手动重写,否则达不到去重的效果
LinkedHashMap集合
我们都知道HashMap的无序性(存储和输出的顺序不一致),但是当我们需要HashMap的唯一性,还想要它能有序的输出,应该怎么做呢?
LinkHashMap可以帮我们解决这个问题:
它是基于哈希表和链接列表实现的
其中HashMap可以解决唯一性的问题,Linked可以解决有序性的问题
例如:
package com.westos.HashMap; import java.util.LinkedHashMap; import java.util.Set; public class LinkedHashMapDome { public static void main(String[] args) { //创建集合对象 LinkedHashMap<String,String> link=new LinkedHashMap<String,String>(); //向集合中添加元素 link.put("迪丽热巴", "美女"); link.put("吴宣仪", "少女"); link.put("孟美岐", "大哥"); link.put("古天乐", "型男"); link.put("萧炎", "斗帝"); //获取集合中所有的键 Set<String> set = link.keySet(); //for循环 for(String key:set) { //获取键对应的值 String value = link.get(key); System.out.println(key+"----"+value); } } } 运行结果: 迪丽热巴----美女 吴宣仪----少女 孟美岐----大哥 古天乐----型男 萧炎----斗帝
TreeMap集合
前面我们学习了treeSet集合,其中了解两种遍历方式:自然排序和比较器排序,接下来让我们看看TreeMap集合
先简单的说说TreeSet与TreeMap的区别?
TreeMap是Map接口常用的子实现类,而TreeSet是Set接口常用的子实现类,TreeSet底层是通过TreeMap来实现的,(就相当于HashSet底层是通过HashMap来实现的),TreeMap是依靠红黑树结构来实现的
相同点:他们都是有序的集合
不同点:他们实现于不同的接口
存储的类型数量不同(treeSet只能存储一种类型,TreeMap可以存储存储两种类型(key和value))
那让我们看看TreeMap存储自定义对象的例子
例如:
先创建一个自定义类
package com.westos.TreeMap; public class Student { private String name; private int age; public Student() { super(); } public Student(String name, int age) { super(); 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; } }
再创建一个测试类:
package com.westos.TreeMap; import java.util.Comparator; import java.util.Set; import java.util.TreeMap; public class TreeMapDome { public static void main(String[] args) { //创建TreeMap集合对象,并且运用比较器排序的方式 TreeMap<Student,String> map=new TreeMap<Student,String>(new Comparator<Student>() { @Override public int compare(Student s1, Student s2) { // return 0; //按年龄(从小到大)来排序 int num=s1.getAge()-s2.getAge(); //当年龄大小一样时,比较姓名 int num2=num==0?s1.getName().compareTo(s2.getName()):num; return num2; } }); //创建学生类对象 Student s1=new Student("旺达",29); Student s2=new Student("幻视",32); Student s3=new Student("黑寡妇",32); Student s4=new Student("雷神",35); Student s5=new Student("托尼",37); Student s6=new Student("托尼",37); //将学生对象添加到集合中 map.put(s1, "菜鸟"); map.put(s2, "美女"); map.put(s3, "御姐"); map.put(s4, "锤子"); map.put(s5, "钢铁侠"); map.put(s6, "小辣椒"); //获取集合中所有的键 Set<Student> set = map.keySet(); for(Student key:set) { //获取键所对应的所有的值 String value = map.get(key); System.out.println(key.getName()+","+key.getAge()+":"+value); } } } 运行结果: 旺达,29:菜鸟 幻视,32:美女 黑寡妇,32:御姐 雷神,35:锤子 托尼,37:小辣椒
前面我们学习了ArrayList集合的嵌套遍历,接下来让我们看看HashMap集合的嵌套
例如:
package com.westos.HashMap2; import java.util.HashMap; import java.util.Set; /** * 一个大集合LPL(中国LOL战队)HashMap<HashMap<Person>> * 三个小集合HashMap<Person> RNG战队,EDG战队,IG战队 * */ public class HashMapTest { public static void main(String[] args) { //创建大集合 HashMap<String,HashMap<String,String>> lol=new HashMap<String,HashMap<String,String>>(); //创建第一个小集合 HashMap<String,String> rng=new HashMap<String,String>(); //向集合中添加元素 rng.put("Uzi", "ADC"); rng.put("Mlxg", "打野"); //将小集合添加到大集合中 lol.put("RNG", rng); //创建第二个小集合 HashMap<String,String> edg=new HashMap<String,String>(); //向集合中添加元素 edg.put("那美", "ADC"); edg.put("厂长", "打野"); //添加到大集合中 lol.put("EDG",edg); //创建第三个小集合 HashMap<String,String> ig=new HashMap<String,String>(); //添加元素 ig.put("Acorn","ADC"); ig.put("Clearlove","打野"); //添加到大集合中 lol.put("IG", ig); //获取大集合中的所有键 Set<String> set = lol.keySet(); //for循环遍历 for(String hash:set) { System.out.println(hash+":"); //获取大集合中的所有值,返回的是小集合的类型 HashMap<String, String> value = lol.get(hash); //然后再获取小集合的所有键,就相当于我们创建一个HashMap集合给他遍历,不要管上面的那些大集合 Set<String> Hashset = value.keySet(); //循环遍历小集合 for(String key:Hashset) { //获取小集合中的所有值 String str = value.get(key); System.out.println("\t"+key+":"+str); } } } } 运行结果: EDG: 厂长:打野 那美:ADC RNG: Uzi:ADC Mlxg:打野 IG: Clearlove:打野 Acorn:ADC
让我们再看看Hashtable与HashMap的区别?
面试题:
HashMap集合和Hashtable的区别?
共同点:都是map接口的实现类,都是基于哈希表的实现类
HashMap集合线程不安全的类,不同步,执行效率高(允许键和值是null的)
Hashtable集合线程安全的类,同步,执行效率低(不允许有null键和null值)
package com.westos.HashMap2; import java.util.HashMap; import java.util.Hashtable; public class HashTable { public static void main(String[] args) { //创建HashMap集合对象 HashMap<String,String> hm=new HashMap<String,String>(); //创建Hashtable集合对象 Hashtable<String,String> ht=new Hashtable<String,String>(); hm.put(null, "java"); //ht.put(null, "baby");//Exception in thread "main" java.lang.NullPointerException System.out.println("hm:"+hm); System.out.println("ht:"+ht); } } 运行结果: hm:{null=java} ht:{}
由上例看出
Hashtable集合不论是键还是值都不允许有null值,否则编译通过,运行就会报错,而HashMap中的则允许有null值,编译和运行都会通过
我们目前学习过的线程安全的类有:StringBuffer(字符串缓冲区)、vector(list集合子实现类)、Hashtable(Map集合子实现类)
让我们用HashMap集合来看一个集合
需求:
字符串:比如: aaaaabbbbcccddddee ,最终控制台要出现的结果:a(5)b(4)c(3)d(3)e(2)
package com.westos.TreeMap; import java.util.HashMap; import java.util.Scanner; import java.util.Set; /** *需求: * 字符串:比如: aaaaabbbbcccddddee ,最终控制台要出现的结果:a(5)b(4)c(3)d(3)e(2) * *思路: * 1)改进:键盘录入一个字符串 * 2)创建一个HashMap集合key:Character,Value:Integer * 3)将录入的字符串转换成字符数组 * 4)遍历可以获取每一个字符 * * 5)将元素添加到对应的HashMap集合中 * 使用的put(key,value): 通过判断值是否null ,如果是null表示第一次存储 * 集合对象.put(ch,1) ; * 否则,不是null * Integer那个值++; * 集合对象.put(ch,变量Integer值) ; * * 6)遍历HashMap集合即可 * */ public class HashMapDome { public static void main(String[] args) { //键盘录入 Scanner sc=new Scanner(System.in); System.out.println("输入一个字符串..."); String str=sc.nextLine(); //将字符春转换成字符数组 char[] array = str.toCharArray(); //创建集合对象 HashMap<Character,Integer> map=new HashMap<Character,Integer>(); //遍历字符数组 for(Character ch:array) { //获取数组中的每一个字符 Integer value = map.get(ch); //判断数组是否为null,如果是给集合中添加元素 if(value==null) { map.put(ch, 1); }else { value++; map.put(ch,value); } } //创建一个字符串缓冲区 StringBuffer sb=new StringBuffer(); //获取集合的键 Set<Character> set = map.keySet(); //遍历HashMap集合的值 for(Character key:set) { //获取集合中的值 Integer num = map.get(key); sb.append(key).append("(").append(num).append(")"); } //将缓冲区中的字符转换成字符串 String str2 = sb.toString(); System.out.println(str2); } } 运行结果: 输入一个字符串... helloworld r(1)d(1)e(1)w(1)h(1)l(3)o(2)