双列集合
特点:
双列集合一次需要存一对数据,分别为键和值
键不能重复,值可以重复
键和值是一一对应的,每个键只能找到自己对应的值
键和值这个整体在Java中叫做“Entry对象”
Map的常见API
Map是双列集合的顶层接口,它的功能是全部双列集合都可以继承使用的
图来自黑马程序员网课
Map的遍历方式
键找值:
Set<String> keys = map2.keySet();
for (String key : keys) {
System.out.println(key + " : " + map2.get(key));
}
键值对:
Set<Map.Entry<String,String>> entries = map2.entrySet();
for (Map.Entry<String,String> entry : entries) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
Lambda表达式:
map2.forEach( (s, s2)-> System.out.println(s2 + " : " + s));
HashMap
特点:
HashMap是Map里的一个实现类;没有额外需要学习的特有方法;
特点都是由键决定的:无序,不重复,无索引
HashMap跟HashSet底层原理一样,都是哈希表结构
底层原理:
以上图来自黑马程序员网课
其原理和HashSet一样,依赖hashCode方法和equals方法保证键的唯一,
若键存储的是自定义对象,需要重写hashCode方法和equals方法,
若值存储的是自定义对象,不需要重写hashCode和equals方法
package com.lazyGirl.mapdemo;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Demo2 {
public static void main(String[] args) {
Map<Student,String> map = new HashMap<Student,String>();
Student s1 = new Student("John", 23);
Student s2 = new Student("Jane", 26);
Student s3 = new Student("Jack", 27);
Student s4 = new Student("Jack", 27);
map.put(s1,"nx");
map.put(s2,"sd");
map.put(s3,"js");
map.put(s4,"js");
Set<Student> set1 = map.keySet();
for (Student student : set1) {
System.out.println(student+" "+map.get(student));
}
System.out.println();
Set<Map.Entry<Student, String>> entries = map.entrySet();
for (Map.Entry<Student, String> entry : entries) {
System.out.println(entry.getKey()+" "+entry.getValue());
}
System.out.println();
map.forEach((key,value) -> System.out.println(key+" "+value));
}
}
输出:
练习2:
package com.lazyGirl.mapdemo;
import java.util.*;
public class Demo3 {
public static void main(String[] args) {
String[] arr = {"A","B","C","D","E","F"};
ArrayList<String> list = new ArrayList<>();
Random rand = new Random();
for (int i = 0; i < 80; i++) {
int num = rand.nextInt(arr.length);
list.add(arr[num]);
}
Map<String,Integer> map = new HashMap<>();
for (String s : list) {
if (map.containsKey(s)) {
map.put(s, map.get(s) + 1);
}else {
map.put(s, 1);
}
}
System.out.println(map);
int max = 0;
String jd = "";
Set<String> set = map.keySet();
for (String s : set) {
if (map.get(s) > max) {
max = map.get(s);
jd = s;
}
}
System.out.println(jd + " " + max);
}
}
输出:
LinkedHashMap
特点:
由键决定:有序,不重复,无索引
这里的有序指的是保证存储和取出的元素顺序一致
实现有序原理:底层数据结构依然是哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序
package com.lazyGirl.mapdemo;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
public class LinkedDemo {
public static void main(String[] args) {
LinkedHashMap<String, Integer> map = new LinkedHashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
map.put("D", 4);
System.out.println(map);
}
}
输出:
TreeMap
特点:
TreeMap跟TreeSet底层原理一样,都是红黑树结构
由键决定特性:不重复,无索引,可排序
可排序:对键进行排序
注意:默认按照键的从小到大进行排序,也可以自己规定键的排序规则
代码书写两种排序规则:
实现Comparable接口,指定比较规则
package com.lazyGirl.mapdemo;
import java.util.Objects;
public class Student implements Comparable<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 String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
int i = this.getAge() - o.getAge();
i = i != 0 ? i : this.getName().compareTo(o.getName());
return i;
}
}
创建集合时传递Comparator比较器对象,指定比较规则 :
public class TreeMapDemo {
public static void main(String[] args) {
TreeMap<Integer,String> treeMap = new TreeMap<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
treeMap.put(1, "A");
treeMap.put(3, "C");
treeMap.put(2, "B");
treeMap.put(4, "D");
System.out.println(treeMap);
}
}
底层源码:
以上三个图来自黑马程序员网课
练习:
package com.lazyGirl.mapdemo;
import java.util.StringJoiner;
import java.util.TreeMap;
public class TreeMapDemo2 {
public static void main(String[] args) {
String target = "aaaajkdjks skasmka";
TreeMap<Character, Integer> map = new TreeMap<Character, Integer>();
for (int i = 0; i < target.length(); i++) {
if (map.containsKey(target.charAt(i))) {
map.put(target.charAt(i), map.get(target.charAt(i)) + 1);
}else {
map.put(target.charAt(i), 1);
}
}
System.out.println(map);
StringBuilder sb = new StringBuilder();
map.forEach((k, v) -> sb.append(k).append("(").append(v).append(")"));
System.out.println(sb);
StringJoiner sj = new StringJoiner(" ","","");
map.forEach((k, v) -> sj.add(k+ "(").add(v + "").add(")"));
System.out.println(sj);
}
}
输出:
TreeMap添加元素的时候,键是否需要重写hashCode和equals方法?不需要
HashMap是哈希表结构,由数组,链表,红黑树组成,既然由有红黑树,是否需要理由Comparable指定排序规则?不需要(因为在HashMap底层,默认理由哈希值大小来创建红黑树的)
TreeMap和HashMap谁的效率更高? HashMap
三种双列集合,如何选择?
默认:HashMap(效率最高) 若保证存取有序:LinkedHashMap 如要进行排序:TreeMap