1. HashMap
1.1 HashMap集合概述和特点
- HashMap底层是哈希表结构的
- 依赖hashCode方法和equals方法保证键的唯一
- 如果键要存储的是自定义对象,需要重写hashCode和equals方法
1.2 HashMap集合应用案例
案例需求
- 创建一个HashMap集合,键是学生对象(Student),值是居住地 (String)。存储多个元素,并
遍历。 - 要求保证键的唯一性:如果学生对象的成员变量值相同,我们就认为是同一个对象
代码实现
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 boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; if (age != student.age) return false; return name != null ? name.equals(student.name) : student.name == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + age; return result; } }
public class HashMapDemo { public static void main(String[] args) { //创建HashMap集合对象 HashMap<Student, String> hm = new HashMap<Student, String>(); //创建学生对象 Student s1 = new Student("刘亦菲", 30); Student s2 = new Student("宋祖儿", 35); Student s3 = new Student("林黛玉", 33); Student s4 = new Student("林黛玉", 33); //把学生添加到集合 hm.put(s1, "西安"); hm.put(s2, "武汉"); hm.put(s3, "郑州"); hm.put(s4, "北京"); //遍历集合 Set<Student> keySet = hm.keySet(); for (Student key : keySet) { String value = hm.get(key); System.out.println(key.getName() + "," + key.getAge() + "," + value); } } }
2. TreeMap
2.1 TreeMap集合概述和特点
- TreeMap底层是红黑树结构
- 依赖自然排序或者比较器排序,对键进行排序
- 如果键存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器
排序规则
2.2 TreeMap集合应用案例一
案例需求
- 创建一个TreeMap集合,键是学生对象(Student),值是籍贯(String),学生属性姓名和年龄,按照年
龄进行排序并遍历 - 要求按照学生的年龄进行排序,如果年龄相同则按照姓名进行排序
代码实现
public class Student implements Comparable<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 String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } @Override public int compareTo(Student o) { //按照年龄进行排序 int result = o.getAge() - this.getAge(); //次要条件,按照姓名排序。 result = result == 0 ? o.getName().compareTo(this.getName()) : result; return result; } }
public class Test1 { public static void main(String[] args) { // 创建TreeMap集合对象 TreeMap<Student,String> tm = new TreeMap<>(); // 创建学生对象 Student s1 = new Student("xiaohei",23); Student s2 = new Student("dapang",22); Student s3 = new Student("xiaomei",22); // 将学生对象添加到TreeMap集合中 tm.put(s1,"江苏"); tm.put(s2,"北京"); tm.put(s3,"天津"); // 遍历TreeMap集合,打印每个学生的信息 tm.forEach( (Student key, String value)->{ System.out.println(key + "---" + value); } ); } }
2.3 TreeMap集合应用案例二
案例需求
- 给定一个字符串,要求统计字符串中每个字符出现的次数。
- 举例: 给定字符串是“aababcabcdabcde”,在控制台输出: “a(5)b(4)c(3)d(2)e(1)”
代码实现
public class Test2 { public static void main(String[] args) { // 给定字符串 String s = "aababcabcdabcde"; // 创建TreeMap集合对象,键是Character,值是Integer TreeMap<Character,Integer> tm = new TreeMap<>(); //遍历字符串,得到每一个字符 for (int i = 0; i < s.length(); i++) { //c依次表示字符串中的每一个字符 char c = s.charAt(i); // 判断当前遍历到的字符是否在集合中出现过 if(!tm.containsKey(c)){ //表示当前字符是第一次出现。 tm.put(c,1); }else{ //存在,表示当前字符已经出现过了 //先获取这个字符已经出现的次数 Integer count = tm.get(c); //自增,表示这个字符又出现了依次 count++; //将自增后的结果再次添加到集合中。 tm.put(c,count); } } // a(5)b(4)c(3)d(2)e(1) //System.out.println(tm); tm.forEach( (Character key,Integer value)->{ System.out.print(key + "(" + value + ")"); } ); } }
3. 总结
HashMap和TreeMap都是常用的Java集合框架中的映射类型,实现了Java中Map接口,并且具有不同的特点和使用场景。
HashMap的特点:
根据键的hashCode值存储数据,因此具有很快的访问速度;
允许使用null作为键和值;
不保证元素的顺序,在遍历元素时无法按照任何顺序输出。
TreeMap的特点:
按照键排序存储数据,因此可以保证元素按照一定顺序输出,这种顺序可以通过key的自然顺序或者自定义排序器决定;
不允许使用null作为键,但可以使用null作为值。在具体使用时,需要根据数据的特点和需要进行选择。
如果需要快速的查找、插入、删除操作,并且对元素的顺序没有特别要求,那么就应该使用HashMap。
如果需要按照键排序并且对元素的顺序有明确要求,那么可以使用TreeMap。同时,在需要在多线程环境下进行操作时,可以使用ConcurrentHashMap来代替HashMap,以保证线程安全。