目录
双列集合
双列集合的特点
集合体系结构
Map的常见API
Map的遍历方式
键找值
键值对
Lambda表达式
底层源码:
HashMap
HashMap的特点
案例
LinkedHashMap
TreeMap
TreeMap基本应用
需求1:
需求2:
案例
可变参数
Collections
Collections常用的API
案例
自动点名器1
自动点名器2
双列集合
双列集合的特点
① 双列集合一次需要存一对数据,分别为键和值
② 键不能重复,值可以重复
③ 键和值是一一对应的,每一个键只能找到自己对应的值
④ 键+值这个整体,我们称之为“键值对”或者“键值对对象”,在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方法的细节:
含义:添加/覆盖
在添加数据的时候,如果键不存在,那么直接把键值对对象添加到map集合当中,方法返回nu11
在添加数据的时候,如果键是存在的,那么会把原有的键值对对象覆盖,会把被覆盖的值进行返回。
package mymap;
import java.util.HashMap;
import java.util.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() | 集合的长度,也就是集合中键值对的个数 |*/
public class MapDemo1 {public static void main(String[] args) {//创建集合对象Map<String, String> map = new HashMap<>();
//添加元素map.put("AAA","aaa");map.put("BBB","bbb");map.put("CCC","ccc");
//打印集合System.out.println(map); //{AAA=aaa, CCC=ccc, BBB=bbb}
System.out.println("----------------------------------------");
//根据键删除键值对元素String result = map.remove("AAA");//打印被删除的值System.out.println(result); //aaa
//打印集合System.out.println(map); //{AAA=aaa, CCC=ccc, BBB=bbb}
System.out.println("----------------------------------------");
//判断集合是否包含指定的键boolean keyResult = map.containsKey("BBB"); //trueSystem.out.println(keyResult);
System.out.println("----------------------------------------");
//判断集合是否包含指定的值boolean valueResult = map.containsValue("bbb");System.out.println(valueResult); //true
System.out.println("----------------------------------------");
//移除所有的键值对元素map.clear();
//打印集合System.out.println(map); //{}
//判断集合是否为空boolean empty = map.isEmpty();System.out.println(empty); //true
//集合的长度,也就是集合中键值对的个数int size = map.size();System.out.println(size); //0
}
}
Map的遍历方式
键找值
获取所有的键,并把这些键放到一个单列集合中,遍历单列集合,得到每一个键,利用map集合中的键获取对应的值
public class MapDemo2 {public static void main(String[] args) {//创建集合对象Map<String, String> map = new HashMap<>();
//添加元素map.put("AAA", "aaa");map.put("BBB", "bbb");map.put("CCC", "ccc");
//遍历集合,键找值Set<String> keyResult = map.keySet();for (String key : keyResult) {String value = map.get(key);System.out.println(key + " = " + value);}}
}
键值对
通过entrySet方法获取所有的键值对对象,返回一个Set集合;
遍历这个Set集合,得到里面每一个键值对对象;
利用getKey() 和 getValue()方法获取键和值
public class MapDemo2 {public static void main(String[] args) {//创建集合对象Map<String, String> map = new HashMap<>();
//添加元素map.put("AAA", "aaa");map.put("BBB", "bbb");map.put("CCC", "ccc");
//遍历集合,键值对Set<Map.Entry<String, String>> entries = map.entrySet();for (Map.Entry<String, String> entry : entries) {String key = entry.getKey();String value = entry.getValue();System.out.println(key + "=" + value);}
}
}
Lambda表达式
方法名称 | 说明 |
---|---|
default void forEach(BiConsumer<? super K,? super V> action) | 结合lambda遍历Map集合 |
利用lambda表达式进行遍历
底层:其实就是利用第二种方式进行遍历,依次得到每一个键和值,再调用accept方法
底层源码:
public class MapDemo4 {public static void main(String[] args) {//创建集合对象Map<String, String> map = new HashMap<>();
//添加元素map.put("AAA", "aaa");map.put("BBB", "bbb");map.put("CCC", "ccc");
//遍历集合,内部类map.forEach(new BiConsumer<String, String>() {@Overridepublic void accept(String s, String s2) {System.out.println(s+"="+s2);}});
System.out.println("-------------------------------------------");
//遍历集合,lambda表达式map.forEach(( s, s2)->System.out.println(s+"="+s2));
}
}
HashMap
HashMap的特点
HashMap是Map里面的一个实现类
直接使用Map里面的方法就可以了
特点都是由键决定的:无序、不重复、无索引
HashMap跟HashSet底层原理是一模一样的,都是哈希表结构
依赖hashcode方法和equals方法保证键的唯一
如果键存储的是自定义对象,需要重写hashcode和equals方法
如果值存储自定义对象,不需要重写hashcode和equals方法
案例
需求 创建一个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;}
/*** 获取* @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;}
@Overridepublic 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);}
@Overridepublic int hashCode() {return Objects.hash(name, age);}
public String toString() {return "Student{name = " + name + ", age = " + age + "}";}
}
/*** 需求* 创建一个HashMap集合,键是学生对象(Student),值是籍贯(String)。存储三个键值对元素,并遍历* 要求:同姓名,同年龄认为是同一个学生*/
public class MapDemo5 {public static void main(String[] args) {//创建map集合对象HashMap<Student,String> map = new HashMap<>();
Student s1 = new Student("zhangsan",23);Student s2 = new Student("lisi",24);Student s3 = new Student("zhangsan",23);
map.put(s1,"陕西");map.put(s2,"山西");map.put(s3,"北京");
map.forEach((Student student, String s)->System.out.println(student + "=" + s));
}
}
需求 某个班级80名学生,现在需要组成秋游活动,班长提供了四个景点依次是A、B、C、D。每个学生只能选择一个景点,请统计出最终哪个景点想去的人数最多。
public class MapDemo6 {public static void main(String[] args) {//利用数组存储4个景点String[] strs = {"A", "B", "C", "D"};//利用随机数模拟80名同学投票ArrayList<String> list = new ArrayList<>();//将投票结果存入listRandom random = new Random();for (int i = 0; i < 80; i++) {int index = random.nextInt(strs.length);list.add(strs[index]);}
//统计HashMap<String, Integer> hashMap = new HashMap<>();//遍历list,将其元素存入mapfor (String s : list) {//如果hashmap里面已经有这个键//获取其值,然后加1if (hashMap.containsKey(s)) {Integer value = hashMap.get(s);value++;hashMap.put(s, value);} else {hashMap.put(s, 1);}}//找出最大值Integer max = 0;Set<String> set = hashMap.keySet();for (String s : set) {if (hashMap.get(s) >= max){max = hashMap.get(s);}}
//找出那个景点,Set<Map.Entry<String, Integer>> entries = hashMap.entrySet();for (Map.Entry<String, Integer> entry : entries) {if (entry.getValue() == max){System.out.println(entry.getKey());}}
}
}
LinkedHashMap
由键决定:有序、不重复、无索引。 这里的有序指的是保证存储和取出的元素顺序一致 原理:底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序,。
public class MapDemo7 {public static void main(String[] args) {
LinkedHashMap<String, Integer> stringIntegerLinkedHashMap = new LinkedHashMap<>();
stringIntegerLinkedHashMap.put("a",1);stringIntegerLinkedHashMap.put("c",3);stringIntegerLinkedHashMap.put("b",2);
System.out.println(stringIntegerLinkedHashMap); //{a=1, c=3, b=2} 存入和取出的元素顺序一致
}
}
TreeMap
TreeMap跟Treeset底层原理一样,都是红黑树结构的。 由键决定特性:不重复、无索引、可排序 可排序:对键进行排序 注意:默认按照键的从小到大进行排序,也可以自己规定键的排序规则 代码书写两种排序规则 实现Comparable接口,指定比较规则, 创建集合时传递Comparator比较器对象,指定比较规则。
TreeMap基本应用
需求1:
键:整数表示id 值:字符串表示商品名称 要求:按照id的升序排列、按照id的降序排列
public class MapDemo8 {public static void main(String[] args) {//创建集合对象,同时处传递Comparator比较器对象,指定比较规则TreeMap<Integer, String> treeMap = new TreeMap<>(( o1, o2)->o2 - o1);//添加元素treeMap.put(1,"奥利奥");treeMap.put(9,"九个核桃");treeMap.put(7,"雷碧");treeMap.put(2,"汪汪");treeMap.put(3,"康帅傅");treeMap.put(5,"哇哈哈哈");
Set<Map.Entry<Integer, String>> entries = treeMap.entrySet();for (Map.Entry<Integer, String> entry : entries) {System.out.print(entry.getKey() + entry.getValue() + " "); //9九个核桃 7雷碧 5哇哈哈哈 3康帅傅 2汪汪 1奥利奥 }}
}
需求2:
键:学生对象 值:籍贯 要求:按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名年龄视为同一个人。
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;}
public String toString() {return "Student{name = " + name + ", age = " + age + "}";}
@Overridepublic int compareTo(Student o) {int i = this.getAge() - o.getAge();i = i == 0 ? this.getName().compareTo(o.getName()) : i;return i;}
}
public class MapDemo9 {public static void main(String[] args) {Student s1 = new Student("zhangsan",23);Student s2 = new Student("lisi",24);Student s3 = new Student("wangwu",25);Student s4 = new Student("a",23);Student s5 = new Student("a",23);TreeMap<Student, String> studentStringTreeMap = new TreeMap<>();studentStringTreeMap.put(s1,"河北");studentStringTreeMap.put(s2,"河南");studentStringTreeMap.put(s3,"北京");studentStringTreeMap.put(s4,"上海");studentStringTreeMap.put(s5,"湖南");
studentStringTreeMap.forEach((Student student, String s)-> System.out.println(student + s) );}
}
案例
统计个数 需求:字符串“aababcabcdabcde” 请统计字符串中每一个字符出现的次数,并按照以下格式输出 输出结果: a(5)b(4)c(3)d(2)e(1)
public class MapDemo10 {public static void main(String[] args) {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)) {Integer integer = tm.get(c);tm.put(c,++integer);}else {tm.put(c,1);}}StringBuilder stringBuilder = new StringBuilder();tm.forEach((Character key, Integer value) -> stringBuilder.append(key).append("(").append(value).append(")"));System.out.println(stringBuilder); //a(5)b(4)c(3)d(2)e(1)}
}
可变参数
在JDK5的时候,出现了可变参数,所谓可变参数,就是方法形参的个数是可以发生变化的 格式 : 属性类型...名字
在底层,可变参数底层就是一个数组
比如,我现在要计算n个整数的和,以前我们先创建一个数组,将整数存入数组中,然后将数组传递给求和的方法,
现在,我们不用自己创建数组了,Java会帮我们创建好
以前,需要我们自己创建数组
public class ArgsDemo {public static void main(String[] args) {int[] arr = {1,2,3,4,5,6,7,8,9,10};System.out.println(getSum(arr));}
public static int getSum(int[] arr){int sum = 0;for (int i = 0; i < arr.length; i++) {sum += arr[i];}return sum;}
}
现在,利用可变参数,Java会帮我们创建数组
public class ArgsDemo {public static void main(String[] args) {System.out.println(getSum(1,2,3,4,5,6,7,8,9,10));}
public static int getSum(int...arr){int sum = 0;for (int i = 0; i < arr.length; i++) {sum += arr[i];}return sum;}
}
细节:
1.在方法的形参中最多只能写一个可变参数 2.在方法的形参当中,如果出了可变参数以外,还有其他的形参,那么可变参数要写在最后
Collections
● java.util.Collections:是集合工具类 ● 作用:Collections不是集合,而是集合的工具类
Collections常用的API
方法名称 | 说明 |
---|---|
public static <T> boolean addAll(Collection<T> c,T... elements) | 批量添加元素 |
public static void shuffle(List<?> list) | 打乱List集合元素的顺序 |
public static <T> void sort(List<T> list) | 排序 |
public static <T> void sort(List<T> list,Comparator <T> c) | 根据指定的规则进行排序 |
public static <T> int binarySearch(List <T> list, T key) | 以二分查找法查找元素 |
public static <T> void copy(List<T> dest,List <T> src) | 拷贝集合中的元素 |
public static <T> int fill(List<T>list, T obj) | 使用指定的元素填充集合 |
public static <T> void max/min(collection <T> coll) | 根据默认的自然排序获取最大/小值 |
public static <T> void swap(List <?> list,int i,int j) | 交换集合中指定位置的元素 |
public class CollectionsDemo {public static void main(String[] args) {ArrayList<Integer> arrayList = new ArrayList<>();
//批量添加元素System.out.println("----------批量添加元素----------");Collections.addAll(arrayList, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
System.out.println(arrayList);System.out.println("------------------------------");
//打乱List集合元素的顺序System.out.println("----------打乱List集合元素的顺序----------");Collections.shuffle(arrayList);
System.out.println(arrayList);System.out.println("------------------------------");
//根据指定的规则进行排序 这里指定倒序System.out.println("----------根据指定的规则进行排序----------");Collections.sort(arrayList, (o1, o2) -> o2 - o1);
System.out.println(arrayList);System.out.println("------------------------------");
//排序 默认整数是从小到大System.out.println("----------排序----------");Collections.sort(arrayList);
System.out.println(arrayList);System.out.println("------------------------------");
//以二分查找法查找元素System.out.println("----------以二分查找法查找元素----------");int i = Collections.binarySearch(arrayList, 1);
System.out.println(i);System.out.println("------------------------------");
//拷贝集合中的元素System.out.println("----------拷贝集合中的元素----------");ArrayList<Integer> arrayList1 = new ArrayList<>();Collections.addAll(arrayList1,0,0,0,0,0,0,0,0,0,0);Collections.copy(arrayList1,arrayList);
System.out.println(arrayList1);System.out.println("------------------------------");
}
}
案例
自动点名器1
班级里有N个学生,实现随机点名器。
public class Test1 {public static void main(String[] args) {//创建集合ArrayList<String> arrayList = new ArrayList<>();//添加元素Collections.addAll(arrayList,"赵一","钱二","孙三","李四","周五","吴六","郑七","王八","冯九","陈十");
//随机1Random random = new Random();System.out.println(arrayList.get(random.nextInt(arrayList.size())));
//随机2Collections.shuffle(arrayList);System.out.println(arrayList.get(0));}
}
自动点名器2
班级里有N个学生,实现随机点名器。 要求: 70%的概率随机到男生 30%的概率随机到女生
public class Test1 {public static void main(String[] args) {//创建集合ArrayList<Integer> arrayList = new ArrayList<>();//添加元素Collections.addAll(arrayList,1,1,1,1,1,1,1,0,0,0);//随机2Collections.shuffle(arrayList);Integer index = arrayList.get(0);
ArrayList<String> boy = new ArrayList<>();ArrayList<String> girl = new ArrayList<>();
Collections.addAll(boy,"赵一","钱二","孙三","李四","周五","吴六","郑七","王八","冯九","陈十");Collections.addAll(girl,"赵女","钱女","孙女","李女","周女");
if (index == 1){Collections.shuffle(boy);System.out.println(boy.get(0));}else {Collections.shuffle(girl);System.out.println(girl.get(0));}}
}