Java笔记_14
一、双列集合
双列集合体系结构:
双列集合的特点:
- 双列集合一次需要存一对数据,分别为键和值
- 键不能重复,值可以重复
- 键和值是一一对应的,每一个键只能找到自己对应的值
- 键+值这个整体我们称之为“键值对”或者“键值对对象”,在Java中叫做“Entry对象”
1.1、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集合中,方法返回null
- 在添加数据的时候,如果键是存在的,那么会把原有的键值对对象覆盖,会把被覆盖的值进行返回。
package Collection_two_Dome.MapDome;
import java.util.HashMap;
import java.util.Map;
public class Dome1 {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("康师傅","kangshufu");
map.put("可口","百事");
map.put("段子","皮皮");
map.put("可口","美年达");//会覆盖上面的可口
map.put("段子","123");
System.out.println(map);
map.remove("康师傅");
System.out.println(map);
System.out.println(map.size());//集合长度
//判断是否存在键
boolean keyResult = map.containsKey("康师傅");
System.out.println(keyResult);
//判断是否存在值
boolean ValueResult = map.containsValue("美年达");
System.out.println(ValueResult);
//清空
map.clear();
System.out.println(map.isEmpty());
System.out.println(map);
}
}
1.2、Map遍历方式一(键找值)
三种遍历方式
- 迭代器遍历
- 增强for遍历
- forEach遍历
package Collection_two_Dome.MapDome;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
public class Dome2 {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("可乐",3);
map.put("康师傅",1);
map.put("汇源",5);
map.put("沙市",4);
Iterator it = map.keySet().iterator();
while (it.hasNext()){
Object next = it.next();
int money = map.get(next);
System.out.println(next +"="+money);
}
System.out.println("--------- ------------------------------");
Set<String> strings = map.keySet();
for (String string : strings) {
int money = map.get(string);
System.out.println(string+"="+money);
}
strings.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
Integer money = map.get(s);
System.out.println(s+"="+money);
}
});
}
}
1.3、Map集合遍历方法二(键值对)
- 利用
entrySet
方法返回一个Set集合 - 这个集合里面装的是键值对对象
- 在通过
get
方法分别得到key
和value
package Collection_two_Dome.MapDome;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Dome3 {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("可乐",3);
map.put("康师傅",1);
map.put("汇源",5);
map.put("沙市",4);
//通过entrySet()方法获得装键值对的set集合
Set<Map.Entry<String, Integer>> entries = map.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
//通过get方法依次得到键和值
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"="+value);
}
}
}
1.4、Map集合遍历方法三(lambda表达式)
方法名称 | 说明 |
---|---|
default void forEach(Biconsumer<? super K,? super V> action) | 结合lambda遍历Map集合 |
package Collection_two_Dome.MapDome;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
public class Dome4 {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("可乐",3);
map.put("康师傅",1);
map.put("汇源",5);
map.put("沙市",4);
map.forEach(new BiConsumer<String, Integer>() {
@Override
public void accept(String s, Integer integer) {
System.out.println(s+"="+ integer);
}
});
System.out.println("-----------------------------------");
map.forEach((String s, Integer integer)->{
System.out.println(s+"="+ integer);
}
);
System.out.println("-----------------------------------");
}
}
1.5、HashMap
HashMap的特点
- HashMap是Map里面的一个实现类。
- 没有额外需要学习的特有方法,直接使用Map里面的方法就可以了。
- 特点都是由键决定的:无序、不重复、无索引
- HashMap跟HashSet底层原理是一模一样的,都是哈希表结构
- 依赖
hashcode
方法和equals
方法保证键的唯一
- 如果键存储的是自定义对象,需要重写hashCode和equals方法
- 如果值存储的是自定义对象,不需要重写hashCode和equals方法
1.6、HashMap练习
package Collection_two_Dome.HashMapDome;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
public class Dome1 {
public static void main(String[] args) {
HashMap<student,String> hm = new HashMap<>();
student s1 = new student("xiaoming",18);
student s2 = new student("xiaowang",19);
student s3 = new student("xiaoli",18);
student s4 = new student("xiaoming",18);
hm.put(s1,"henan");
hm.put(s2,"guangdong");
hm.put(s3,"jiangsu");
hm.put(s4,"shandong");
hm.forEach((student student, String s)->{
System.out.println(student+" "+s);
}
);
System.out.println("-------------------------------------");
Set<Map.Entry<student, String>> hms = hm.entrySet();
for (Map.Entry<student, String> studentStringEntry : hms) {
System.out.println(studentStringEntry);
}
System.out.println("-------------------------------------");
Iterator it = hm.entrySet().iterator();
while (it.hasNext()){
Object next = it.next();
System.out.println(next);
}
}
}
package Collection_two_Dome.HashMapDome;
import java.util.*;
public class Dome2 {
public static void main(String[] args) {
//创建数组,记录四个景点
String[] arr = {"黄山","泰山","华山","佘山"};
//利用随机数模拟80个同学的投票票
//通过集合的形式记录每个景点的票数
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]);
}
//定义Map集合,利用集合进行统计
HashMap<String,Integer> hm = new HashMap<>();
for (String name : list) {
//判断当前景点在map集合中是否存在
if(hm.containsKey(name)){
//先得到这个景点的次数
int count = hm.get(name);
//在进行++
count++;
//重新存入
hm.put(name,count);
}else {
hm.put(name,1);
}
}
System.out.println(hm);
//求最大值
int max = 0;
//比较得出最大值
Set<Map.Entry<String, Integer>> entries = hm.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
if(entry.getValue()>max){
max= entry.getValue();
}
}
System.out.println(max);
//再次通过遍历的到最大票数的景点
for (Map.Entry<String, Integer> entry : entries) {
if (max== entry.getValue()){
System.out.println(entry.getKey());
}
}
}
}
1.7、HashMap底层源码解析
数组位置为null
数组位置不为null,键不重复,挂在下面形成链表或者红黑树
1.8、LinkedHashMap
- 由键决定:有序、不重复、无索引。
- 这里的有序指的是保证存储和取出的元素顺序一致
- 原理∶底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序。
package Collection_two_Dome.LinkedHashMapDome;
import java.util.LinkedHashMap;
public class Dome1 {
public static void main(String[] args) {
LinkedHashMap<String,Integer> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("可乐",3);
linkedHashMap.put("百事",3);
linkedHashMap.put("沙市",4);
linkedHashMap.put("北冰洋",5);
linkedHashMap.put("可口",3);
linkedHashMap.put("芬达",3);
linkedHashMap.put("雪碧",3);
linkedHashMap.put("可乐",4);//键相同时,回覆盖掉原来的值
System.out.println(linkedHashMap);
}
}
1.9、TreeMap
- TreeMap跟TreeSet底层原理一样,都是红黑树结构的。
- 由键决定特性:不重复、无索引、可排序
- 可排序:对键进行排序。
- 注意:默认按照键的从小到大进行排序,也可以自己规定键的排序规则
代码书写两种排序规则
- 实现Comparable接口,指定比较规则。
- 创建集合时传递Comparator比较器对象,指定比较规则。
package Collection_two_Dome.TreeMapDome;
import java.util.Comparator;
import java.util.TreeMap;
public class Dome1 {
public static void main(String[] args) {
TreeMap<Integer,String> tm = new TreeMap<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;//此时Integer按照降序排列
}
});
//默认情况下Integer 和Double类型是按照升序的方法进行排列
tm.put(1,"火车");
tm.put(4,"游艇");
tm.put(5,"出租");
tm.put(2,"公交");
tm.put(7,"大巴");
tm.put(6,"汽车");
tm.put(8,"飞机");
System.out.println(tm);
}
}
package Collection_two_Dome.TreeMapDome;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class Dome2 {
public static void main(String[] args) {
TreeMap<Student,String> tm = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int i = o1.getAge()- o2.getAge();
i = i==0?o1.getName().compareTo(o2.getName()):i;
return i;
}
});
Student s1 = new Student("chen",18);
Student s2 = new Student("lu",19);
Student s3 = new Student("huang",17);
Student s4 = new Student("jia",19);
Student s5 = new Student("qian",18);
Student s6 = new Student("gao",20);
tm.put(s1,"广东");
tm.put(s2,"河南");
tm.put(s3,"四川");
tm.put(s4,"山西");
tm.put(s5,"江苏");
tm.put(s6,"云南");
Set<Map.Entry<Student, String>> entries = tm.entrySet();
for (Map.Entry<Student, String> entry : entries) {
System.out.println(entry);
}
}
}
package Collection_two_Dome.TreeMapDome;
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;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
package Collection_two_Dome.TreeMapDome;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
import java.util.TreeMap;
import java.util.function.BiConsumer;
public class Dome3 {
public static void main(String[] args) {
String s = "asdasdasdasdasdddasdasdaddadfffaasffafasffff";
TreeMap<Character,Integer> tm = new TreeMap<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if(tm.containsKey(c)){
Integer count = tm.get(c);
count++;
tm.put(c,count);
}else {
tm.put(c,1);
}
}
StringBuilder sb = new StringBuilder();
tm.forEach((character,integer)->sb.append(character).append("(").append(integer).append(")"));
System.out.println(sb);
//使用StringJoiner方法时需要定义开头末尾以及中间每个元素之间的间隔字符
StringJoiner sj =new StringJoiner("","","");/*使用StringJoiner的add方法时一定要添加字符串&*/
tm.forEach(( character, integer)->sj.add(character+"").add("(").add(integer+"").add(")"));
System.out.println(sj);
}
}
1.10、TreeMap源码解析
二、集合练习
2.1、可变参数
- 可变参数本质上就是一个数组
- 作用:在形参中接收多个数据
- 格式:
数据类型...参数名称
- 举例:
int...a
- 注意事项:
- 形参列表中可变参数只能有一个
- 可变参数必须放在形参列表的最后面
package Collection_two_Dome.Args_Collections;
import com.sun.source.tree.ReturnTree;
public class Dome1 {
public static void main(String[] args) {
System.out.println(Addall(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
}
public static int Addall(int... a){
int sum = 0;
for (int i = 0; i < a.length; i++) {
sum = sum + a[i];
}
return sum;
}
}
2.2、Collections
- java.util.Collections:是集合工具类
- 作用:Collections不是集合,而是集合的工具类。
方法名称 | 说明 |
---|---|
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) | 交换集合中指定位置的元素 |
package Collection_two_Dome.Args_Collections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Dome2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>();
//在集合里面批量添加元素
Collections.addAll(list,"asd","qwewq","zxczxc","jghjgh","yuiuyiu","bnmbmn");
System.out.println(list);
//打乱集合的顺序
Collections.shuffle(list);
System.out.println(list);
//对集合进行排序(默认是从小到大)
Collections.sort(list);
System.out.println(list);
//按照指定规则对集合进行排序(匿名内部类中重写)
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
int i = o2.compareTo(o1);
return i;
}
});
System.out.println(list);
//通过二分法进行查找
System.out.println(Collections.binarySearch(list, "qwewq"));
//使用该方法必须让被拷贝添加的数组有长度,且大于等于拷贝数组
Collections.addAll(list2,new String[list.size()]);
Collections.copy(list2,list);
System.out.println(list2);
//获取集合最大值/最小值
System.out.println(Collections.max(list));
System.out.println(Collections.min(list));
//交换集合中指定元素的位置
Collections.swap(list,0,list.size()-1);
System.out.println(list);;
//使用指定元素添加给集合
Collections.fill(list,"12321");
System.out.println(list);
}
}
2.3、综合练习
package Collection_two_Dome.Exam;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
public class Test1 {
public static void main(String[] args) {
//班级里有N个学生,实现随机点名器。
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"xiaoming","xiaowang","xiaohong","xiaoli","xiaozhang","xiaolu","xiaochang");
Random r = new Random();
System.out.println(list.get(r.nextInt(list.size())));
Collections.shuffle(list);
System.out.println(list.get(r.nextInt(list.size())));
}
}
package Collection_two_Dome.Exam;
import java.util.*;
public class Test2 {
public static void main(String[] args) {
/*
班级里有N个学生要求:
70%的概率随机到男生
30%的概率随机到女生
*/
//创建一个集合存放0和1,其中1代表男生,0代表女生
//这个集合中1的数量为7,0的数量为3
//随机抽取出来的概率就是男生70%女生30%
ArrayList<Integer> integers = new ArrayList<>();
Collections.addAll(integers,1,1,1,1,1,1,1);
Collections.addAll(integers,0,0,0);
Random r = new Random();
int index = integers.get(r.nextInt(integers.size()));
//创建男生集合
ArrayList<String> man = new ArrayList<>();
Collections.addAll(man,"男1","男2","男3","男4","男5","男6","男7","男8");
//创建女生集合
ArrayList<String> woman = new ArrayList<>();
Collections.addAll(woman,"女1","女2","女3","女4","女5","女6","女7","女8");
if (index == 1){
System.out.println(man.get(r.nextInt(man.size())));
} else if (index == 0) {
System.out.println(woman.get(r.nextInt(man.size())));
}
}
}
package Collection_two_Dome.Exam;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
public class Test3 {
public static void main(String[] args) {
/*
* 班级里有N个学生
* 要求:
被点到的学生不会再被点到。
但是如果班级中所有的学生都点完了,需要重新开启第二轮点名
* */
ArrayList<String> list1 = new ArrayList<>();
//定义一个集合来获取第一个集合删除的元素
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list1,"xiangwang","xianghuang","xiangli","xiangzhang","xianglu","xiangzhao","xianglong","xiangtian");
Random r = new Random();
for (int i = 0; i < 10 ; i++) {
int count = list1.size();
for (int j = 0; j < count; j++) {
//remove(index)该方法会返回删除的结果
String name = list1.remove(r.nextInt(list1.size()));
list2.add(name);
System.out.println(name);
}
//给第list1重新添加回数据,并且清空list2以便重新点名
list1.addAll(list2);
list2.clear();
System.out.println("------------------------------");
}
}
}
- 该案例回到后面完成
package Collection_two_Dome.Exam;
import java.util.*;
import java.util.function.BiConsumer;
public class Test4 {
public static void main(String[] args) {
HashMap<String, ArrayList<String>> hm = new HashMap<>();
ArrayList<String> list1 = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>();
ArrayList<String> list3 = new ArrayList<>();
ArrayList<String> list4 = new ArrayList<>();
Collections.addAll(list1,"南京市","扬州市","苏州市","镇江市","盐城市","徐州市");
Collections.addAll(list2,"郑州市","周口市","洛阳市","开封市","商丘市","焦作市");
Collections.addAll(list3,"广州市","深圳市","东莞市","湛江市","茂名市","汕头市");
Collections.addAll(list4,"武汉市","鄂州市","黄冈市","孝感市","宜昌市","十堰市");
hm.put("江苏",list1);
hm.put("河南",list2);
hm.put("广东",list3);
hm.put("湖北",list4);
Set<Map.Entry<String, ArrayList<String>>> entries = hm.entrySet();
for (Map.Entry<String, ArrayList<String>> entry : entries) {
String key = entry.getKey();
ArrayList<String> value = entry.getValue();
StringJoiner sj = new StringJoiner(",","","");
for (String s : value) {
sj.add(s);
}
System.out.println(key+"="+sj);
}
}
}