双列集合的特点
双列集合一次需要存一对数据,分别为键和值
键不能重复,值可以重复
键和值是一一对应的,每一个键只能找到自己对应的值
键+值这个整体 ,我们称之为“键值对”或者“键值对对象”,在Java中叫做“Entry对象”
Map的常见API
Map是双列集合的顶层接口,它的功能是全部双列集合都可以继承使用的
V put(K key,v value) 添加元素
V remove(object key) 根据键删除键值对元素
void clear() 移除所有的键值对元素
boolean containsKey(object key) 判断集合是否包含指定的键
boolean containsValue(object value) 判断集合是否包含指定的值
boolean isEmpty() 判断集合是否为空
int size() 集合的长度,也就是集合中键值对的个数
put 添加元素
那么这个返回值是什么呢?我们来试试看添加第二个"张三"
可以看到返回的是18,是"张三"之前对应的值,再来看看👇
还没有添加第二个”张三“的时候,返回的是null
总结:
在添加数据的时候,如果键不存在,那么直接把键值对对象添加到map集合当中,方法返回null
在添加数据的时候,如果键是存在的,那么会把原有的键值对对象覆盖,会把被覆盖的值进行返回。
V remove(object key) 根据键删除键值对元素
可以看到返回的是删除键所对应的值
void clear() 移除所有的键值对元素
清空了
boolean containsKey(object key) 判断集合是否包含指定的键
boolean containsValue(object value) 判断集合是否包含指定的值
boolean isEmpty() 判断集合是否为空
如果我给数据清空了,就是👇这样
int size() 集合的长度,也就是集合中键值对的个数
Map的遍历方式
键找值
装着健的单列集合使用增强for形式进行遍历
装着健的单列集合使用迭代器形式进行遍历
装着健的单列集合使用lambda表达式形式进行遍历
键值对
装着健值对的单列集合使用增强for形式进行遍历
装着健值对的单列集合使用迭代器形式进行遍历
装着健值对的单列集合使用lambda表达式形式进行遍历![](https://img-blog.csdnimg.cn/direct/46144259c57e4f5297b18a191ae32ba1.png)
lambda表达式
HashMap的特点
- HashMap是Map里面的一个实现类,
- 没有额外需要学习的特有方法,直接使用Map里面的方法就可以了
- 特点都是由键决定的:无序、不重复、无索引
- HashMap跟Hashset底层原理是一模一样的,都是哈希表结构
HashMap底层是哈希表结构的
依赖hashcode方法和equals方法保证键的唯一
如果键存储的是自定义对象,需要重写hashCode和equals方法
如果值存储自定义对象,不需要重写hashcode和equals方法
练习
1、创建一个HashMap集合,键是学生对象(Student),值是籍贯(String)。
存储三个键值对元素,并遍历
要求:同姓名,同年龄认为是同一个学生
HashMap的键位置如果存储的是自定义对象,需要重写hashcode和equals方法。
先写Student类
package Map;
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param 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;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapTest1 {
public static void main(String[] args) {
/*创建一个HashMap集合,键是学生对象(Student),值是住址(String)。
存储三个键值对元素,并遍历
要求:同姓名,同年龄认为是同一个学生*/
HashMap<Student,String>hm=new HashMap<>();
Student s1=new Student("张三",18);
Student s2=new Student("李四",20);
Student s3=new Student("王五",25);
hm.put(s1,"北京");
hm.put(s2,"南京");
hm.put(s3,"上海");
//遍历集合
//第一种方法键找值
Set<Student> keys = hm.keySet();
for (Student key : keys) {
System.out.println(key+"="+hm.get(key));
}
System.out.println("--------------------------------------");
//第二种方法键值对
Set<Map.Entry<Student, String>> entries = hm.entrySet();
for (Map.Entry<Student, String> entry : entries) {
System.out.println(entry.getKey()+"="+entry.getValue());
}
System.out.println("--------------------------------------");
//第三种方法lambda表达式
hm.forEach((student, s) ->System.out.println(student+"="+s));
}
}
2、某个班级80名学生,现在需要组成秋游活动,班长提供了四个景点依次是(A、B、C、D),每个学生只能选择一个景点,请统计出最终哪个景点想去的人数最多。
package Map;
import java.util.*;
public class MapTest2 {
public static void main(String[] args) {
String[] arr={"A","B","C","D"};
Random r=new Random();
ArrayList<String>list=new ArrayList<>();
//将
for (int i = 0; i < 80; i++) {
int index = r.nextInt(arr.length);
list.add(arr[index]);
}
HashMap<String,Integer>hm=new HashMap<>();
for (String s : list) {
if(hm.containsKey(s)){
//存在
Integer count = hm.get(s);
count++;
hm.put(s,count);
}
else{
//不存在
hm.put(s,1);
}
}
System.out.println(hm);
//求最大值
Set<Map.Entry<String, Integer>> entries = hm.entrySet();
int max=0;
for (Map.Entry<String, Integer> entry : entries) {
if (entry.getValue()>max) {
max=entry.getValue();
}
}
//确定哪个景点的次数与最大值一样
for (Map.Entry<String, Integer> entry : entries) {
if (entry.getValue()==max) {
System.out.println(entry.getKey());
}
}
}
}
LinkedHashMap
由键决定:有序、不重复、无索引。
这里的有序指的是保证存储和取出的元素顺序一致
原理:底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序
与hashmap一样键也是唯一的
这里我给存储的顺序打乱了👇
可以看到存取顺序一致
TreeMap
TreeMap跟TreeSet底层原理一样,都是红黑树结构的。
由键决定特性:不重复、无索引、可排序
可排序:对键进行排序。
注意:默认按照键的从小到大进行排序,也可以自己规定键的排序规则
代码书写两种排序规则
- 实现Comparable接口,指定比较规则。
- 创建集合时传递Comparator比较器对象,指定比较规则。
练习
1、键;整数表示id 值:字符串表示商品名称 要求:按照id的升序排列、按照id的降序排列
id的升序排列👇
package Map;
import java.util.Comparator;
import java.util.TreeMap;
public class TreeMapTest1 {
public static void main(String[] args) {
/* 键;整数表示id
值:字符串表示商品名称
要求:按照id的升序排列、按照id的降序排列*/
TreeMap<Integer,String>tm=new TreeMap<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});
tm.put(1,"张三");
tm.put(3,"王五");
tm.put(2,"李四");
System.out.println(tm);
}
}
id的降序排列👇
o1:当前要添加的元素
o2:表示已经在红黑树中存在的元素
2、键:学生对象 值:籍贯 要求:按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名年龄视为同一个人
Student类
package Map;
import java.util.Objects;
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;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param 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;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
@Override
public int compareTo(Student o) {
//this:表示当前要添加的元素
// o:表示已经在红黑树中存在的元素
/*返回值:
负数:表示当前要添加的元素是小的,存左边
正数:表示当前要添加的元素是大的,存右边
0:表示当前要添加的元素已经存在,舍弃*/
int i=this.getAge()-o.getAge();
i = i == 0 ? this.getName().compareTo(o.getName()) : i;
return i;
}
}
测试类
package Map;
import java.util.TreeMap;
public class TreeMapTest2 {
public static void main(String[] args) {
/*键:学生对象
值:籍贯
要求:按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名年龄视为同一个人*/
TreeMap<Student,String>tm=new TreeMap<>();
Student s1=new Student("张三",18);
Student s3=new Student("王五",22);
Student s2=new Student("李四",20);
tm.put(s1,"北京");
tm.put(s2,"南京");
tm.put(s3,"上海");
System.out.println(tm);
}
}
3、字符串:"aababcabcdabcde”请统计字符串中每一个字符出现的次数,并按照以下格式输出输出结果:a(5)b(4)c(3)d(2)e(1)
package Map;
import java.util.TreeMap;
import java.util.function.BiConsumer;
public class TreeMapTest3 {
public static void main(String[] args) {
/*字符串:"aababcabcdabcde"
请统计字符串中每一个字符出现的次数,
并按照以下格式输出输出结果:a(5)b(4)c(3)d(2)e(1)*/
String str="aababcabcdabcde";
TreeMap<Character,Integer>tm=new TreeMap<>();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if(tm.containsKey(c)){
//存在
int count=tm.get(c);
count++;
tm.put(c,count);
}else{
//不存在
tm.put(c,1);
}
}
//遍历集合,并按照指定的格式进行拼接
StringBuilder sb = new StringBuilder();
tm.forEach(new BiConsumer<Character, Integer>() {
@Override
public void accept(Character key, Integer value) {
sb.append(key).append("(").append(value).append(")");
}
});
System.out.println(sb);
}
}
这一期就到这里啦!!!感谢观看!!!
努力遇见更好的自己!!!