一、Map集合
1.在生活中,存在一种对应关系的集合。比如:IP地址与主机名,身份证号与个人。这种对应关系叫做映射。Java中提供了专门的集合类即Map集合用来存放这种对象关系的对象。
2.Map接口与Collection接口的不同:
Map是双列的,Collection是单列的
Map的键唯一,Collection的子体系Set是唯一的
Map集合的数据结构针对键有效,跟值无关;Collection集合的数据结构是针对元素有效
Collection中的集合,元素是孤立存在的,向集合中存储元素采用一个个元素的方式存储
Map中的集合,元素是成对存在的。每个元素都有键和值两部分组成,通过键可以找到对应的值
Map集合中不能包含重复的键,值可以重复。每个键只能对应一个值。
1.1 Map集合的方法
public V put(K key, V value) : 把指定的键与指定的值添加到Map集合中。
public V remove(Object key) : 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
public V get(Object key) 根据指定的键,在Map集合中获取对应的值。
public Set<K> keySet() : 获取Map集合中所有的键,存储到Set集合中。
public Set<Map.Entry<K,V>> entrySet() : 获取到Map集合中所有的键值对对象的集合(Set集合)。
public class MapDemo1 {
public static void main(String[] args) {
/*HashMap 键值对
键的数据结构是哈希表(无序),所有的双列集合的数据结构只和键有关,与值无关*/
//创建一个map对象
HashMap<String, String> map = new HashMap<>();
/*public V put(K key, V value) : 把指定的键与指定的值添加到Map集合中
使用put方法时,若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中;
若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。
*/
map.put("AAA","aaa");
map.put("BBB","bbb");
map.put("CCC","ccc");
String s = map.put("CCC", "ddd");
System.out.println(s);//ccc
System.out.println(map);//{AAA=aaa, CCC=ccc, BBB=bbb}
//public V remove(Object key) : 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
System.out.println(map.remove("AAA"));//aaa
System.out.println(map);//{CCC=ccc, BBB=bbb}
//public V get(Object key) 根据指定的键,在Map集合中获取对应的值。
System.out.println(map.get("BBB"));//bbb
System.out.println(map.get("sss"));//null
System.out.println(map);//{CCC=ccc, BBB=bbb}
/*
判断功能
boolean containsKey(Object key):判断集合是否包含指定的键
boolean containsValue(Object value):判断集合是否包含指定的值
boolean isEmpty():判断集合是否为空
*/
boolean b = map.containsKey("AAA");
System.out.println(b);//false
boolean b1 = map.containsValue("bbb");
System.out.println(b1);//true
System.out.println(map.isEmpty());//false
/*
删除功能
void clear():移除所有的键值对元素
V remove(Object key):根据键删除键值对元素,并把值返回
*/
String s1 = map.remove("BBB");
System.out.println(s1);//bbb
map.clear();
System.out.println(map.isEmpty());//true
}
}
1.2 Map 集合遍历键找值方式
(1)键找值方式
通过元素中的键,获取到键所对应的值
步骤:
1.获取Map中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键。方法提示: keyset()
2. 遍历键的Set集合,得到每一个键。
3. 根据键,获取键所对应的值。
代码:
import java.util.HashMap;
import java.util.Set;
public class MapDemo02 {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("AAA","aaa");
map.put("BBB","bbb");
map.put("CCC","ccc");
//获取所有的键,获取到键的一个集合
Set<String> keySet = map.keySet();
//遍历键的集合,得到每一个键
for (String key : keySet) {
//通过get方法获取对应的值
String value = map.get(key);
System.out.println(value);
}
}
}
(2)键值对对象找键与值
键值对方式:即通过集合中每个键值对(Entry)对象,获取键值对(Entry)对象中的键与值
步骤:
- 获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回。方法提示: entrySet() 。
- 遍历包含键值对(Entry)对象的Set集合,得到每一个键值对(Entry)对象。
- 通过键值对(Entry)对象,获取Entry对象中的键与值。
代码:
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapDemo03 {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("AAA","aaa");
map.put("BBB","bbb");
map.put("CCC","ccc");
获取所有的键值对entry对象,以Set集合形式返回
Set<Map.Entry<String, String>> entries = map.entrySet();
//遍历得到每个键值对entry对象
for (Map.Entry<String, String> entry : entries) {
//获取键
String key = entry.getKey();
String value = entry.getValue();
System.out.println("值:"+key+"对应的值是--->"+value);
/*
值:AAA对应的值是--->aaa
值:CCC对应的值是--->ccc
值:BBB对应的值是--->bbb
*/
}
}
}
1.3 HashMap集合存储自定义类型键值
HashMap集合键是String类型,值是自定义Student类型。
自定义Student
public class 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 + '}';
}
}
测试类:
public class Test {
public static void main(String[] args) {
//存储一个键为String类型,值为Student类型
HashMap<String, Student> hashMap = new HashMap<>();
hashMap.put("s001",new Student("张三",20));
hashMap.put("s002",new Student("李四",21));
hashMap.put("s003",new Student("王五",22));
System.out.println(hashMap);
//使用键值对entrySet方法遍历集合元素,打印学生信息
for (Map.Entry<String, Student> entry : hashMap.entrySet()) {
String name = entry.getValue().getName();
int age = entry.getValue().getAge();
String key = entry.getKey();
System.out.println("序号"+key+","+"姓名"+name+","+"年龄"+age);
}
//方法2
Set<String> keys = hashMap.keySet();
for (String key : keys) {
Student student = hashMap.get(key);
int age = student.getAge();
String name = student.getName();
System.out.println("序号"+key+","+"姓名"+name+","+"年龄"+age);
}
//方法3 迭代器
Set<Map.Entry<String, Student>> entrySet = hashMap.entrySet();
Iterator<Map.Entry<String, Student>> iterator = entrySet.iterator();
while (iterator.hasNext()){
Map.Entry<String, Student> entry = iterator.next();
int age = entry.getValue().getAge();
String name = entry.getValue().getName();
String key = entry.getKey();
System.out.println("序号"+key+","+"姓名"+name+","+"年龄"+age);
}
}
}
HashMap集合键是自定义Student类型,值是自定义String类型。
由于HashMap集合的特点是键唯一,所以自定义Student类需要重写hashCode方法 和 equals 方法
在上述Student类中加入hashCode方法 和 equals 方法
@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 class StudentTest {
public static void main(String[] args) {
HashMap<Student, String> hashMap = new HashMap<>();
hashMap.put(new Student("李四",28),"上海");
hashMap.put(new Student("王五",25),"北京");
hashMap.put(new Student("赵六",28),"西安");
Set<Student> keySet = hashMap.keySet();
for (Student student : keySet) {
String address = hashMap.get(student);
System.out.println(student.toString()+"----->"+address);
}
}
}
给 HashMap中存放自定义对象时,如果自定义对象作为key存在,这时要保证对象唯一,必须复写对象的hashCode和equals方法
原因:由于没有重写hashcode方法,所以在往HashMap中存放元素时依旧调用的是Object类的hashcode方法,返回的是对象的内存地址。
那么在重写了hashcode方法,这里面的hashcode方法返回的id值是hashcode值,如果两个对象的内容相同,那么他们两个的hash值是相同的。但是这时不一定能够保证两个对象的hashcode值相同,因为我们只重写了hashcode方法,并没有重写equals方法。HashMap是用链地址法来处理碰撞冲突的,就是说,一条链表上的元素的hashcode返回的hash值是相同的。重写hashCode方法只能证明两个对象的hash直相同,由于没有重写equals方法,所以并不一定相同。这是会调用Object类的equlas方法,判断的依旧是地址值,由于对象是new出来的,地址值是不一样的。所以,当 HashMap中存放自定义对象时,必须重写对象的hashCode和equals方法。
1.4 LinkedHashMap集合存储自定义类型键值
HashMap集合能够保证元素唯一,并且查询速度快,但是并不能保证存取顺序相同,那么LinkedHashMap作为HashSet的子类。
LinkedHashMap的特点:
- 底层的数据结构是链表加哈希表,哈希表能够保证元素唯一,链表能够保证元素有序
- Map集合的数据结构只和键有关
public class LinkedHashMapDemo {
public static void main(String[] args) {
//底层哈希表+链表 链表保证有序
HashMap<String,String> map=new LinkedHashMap<>();
map.put("a","aa");
map.put("b","bb");
map.put("c","cc");
map.put("a","dd");
System.out.println(map);//{a=dd, b=bb, c=cc}
}
}
1.5 TreeMap集合存储自定义类型键值
TreeMap集合特点
- 键的数据结构是红黑树,可以保证键的排序和唯一性
- TreeMap排序分为自然排序和比较器排序
- 线程不安全,效率高
TreeMap集合键是String值是String的案例
public class MyTest {
public static void main(String[] args) {
TreeMap<String, String> treeMap = new TreeMap<>();
treeMap.put("aaa","AAA");
treeMap.put("bbb","BBB");
treeMap.put("ccc","CCC");
treeMap.put("ccc","DDD");
System.out.println(treeMap);//{aaa=AAA, bbb=BBB, ccc=DDD}
}
}
TreeMap集合键是自定义类Student 值是String的案例
自定义类Student
//Student类实现Comparator接口
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", 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;
}
//重写compareTo方法
@Override
public int compareTo(Student o) {
int num= this.age-o.age;
int num2=num==0?this.name.compareTo(o.name):num;
return num2;
}
}
测试类:
public class TreeMapDemo01 {
public static void main(String[] args) {
/*
排序:
1.自然排序,使用空参构造,对键有有一定的要求,必须实现Comparable接口
*/
//双列集合的数据结构,只和键有关
//对键进行自然排序,键需要实现Comparator接口 Student类实现Comparator接口
TreeMap<Student,String> treeMap = new TreeMap<>();
treeMap.put(new Student("张三",23),"001");
treeMap.put(new Student("张三2",24),"002");
treeMap.put(new Student("张三3",25),"003");
treeMap.put(new Student("张三4",26),"004");
treeMap.put(new Student("张三5",27),"005");
treeMap.put(new Student("张三6",28),"006");
treeMap.put(new Student("张三7",29),"007");
System.out.println(treeMap);
for (Map.Entry<Student, String> studentStringEntry : treeMap.entrySet()) {
String value = studentStringEntry.getValue();
Student key = studentStringEntry.getKey();
System.out.println(key+value);
}
}
}
在构建TreeMap对象时,参数传入比较器Comparator 重写compare方法
public class TreeMapDemo02 {
public static void main(String[] args) {
//参数传入比较器排序 重写compare方法
TreeMap<Student,String> treeMap = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//按着姓名长度排序
int num=o1.getName().length()-o2.getName().length();
int num2=num==0?o1.getName().compareTo(o2.getName()):num;
return num2;
}
});
treeMap.put(new Student("张三",23),"001");
treeMap.put(new Student("张三2sss",24),"002");
treeMap.put(new Student("张三3ddd",25),"003");
treeMap.put(new Student("张三4",26),"004");
treeMap.put(new Student("张三5",27),"005");
treeMap.put(new Student("张三6",28),"006");
treeMap.put(new Student("张三7",29),"007");
for (Map.Entry<Student, String> studentStringEntry : treeMap.entrySet()) {
String value = studentStringEntry.getValue();
Student key = studentStringEntry.getKey();
System.out.println(key+value);
}
}
}
1.6 Map集合练习
统计一个字符串中每个字符出现的次数
public class MyTest01 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("输入一个字符串");
String s = sc.nextLine();
HashMap<Character, Integer> hashMap = new HashMap<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (!hashMap.containsKey(c)){
hashMap.put(c,1);
}else {
Integer count = hashMap.get(c);
hashMap.put(c,++count);
}
}
for (Map.Entry<Character, Integer> entry : hashMap.entrySet()) {
Character key = entry.getKey();
Integer value = entry.getValue();
//System.out.print(key+"("+value+")"+" ");
StringBuilder stringBuilder = new StringBuilder();
StringBuilder append = stringBuilder.append(key).append("(").append(value).append(")");
System.out.println(append);
}
}
}
执行结果:
二、集合嵌套
集合嵌套之HashMap嵌套HashMap
public class MapAndMap {
public static void main(String[] args) {
HashMap<HashMap<String, String>, String> hashMap = new HashMap<>();
HashMap<String, String> hashMap1 = new HashMap<>();
hashMap1.put("张三","20");
hashMap1.put("李四","22");
HashMap<String, String> hashMap2 = new HashMap<>();
hashMap2.put("王五","24");
hashMap2.put("赵六","26");
hashMap.put(hashMap1,"第一组");
hashMap.put(hashMap2,"第二组");
//集合遍历 ,获取一个Set集合 元素为HashMap集合
Set<HashMap<String, String>> maps = hashMap.keySet();
for (HashMap<String, String> map : maps) {
//遍历每个元素HashMap
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"+key+" ,Value"+value);
}
}
}
}
集合嵌套之ArrayList嵌套HashMap
public class ListAndMap {
public static void main(String[] args) {
ArrayList<HashMap<String,String>> arrayList = new ArrayList<>();
HashMap<String, String> hashMap1 = new HashMap<>();
hashMap1.put("周瑜","小乔");
hashMap1.put("吕布","貂蝉");
HashMap<String, String> hashMap2 = new HashMap<>();
hashMap2.put("郭靖","黄蓉");
hashMap2.put("杨过","小龙女");
HashMap<String, String> hashMap3 = new HashMap<>();
hashMap3.put("令狐冲","任盈盈");
hashMap3.put("林平之","岳灵珊");
arrayList.add(hashMap1);
arrayList.add(hashMap2);
arrayList.add(hashMap3);
//集合遍历
for (HashMap<String, String> hashMap : arrayList) {
for (Map.Entry<String, String> entry : hashMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println("\t"+key+"---"+value);
}
}
}
}
HashMap和Hashtable的区别
HashMap: 线程不安全,效率高.允许null值和null键
Hashtable: 线程安全 , 效率低.不允许null值和null键
三、Collections工具类
public class Collections {
public static void main(String[] args) {
/*
集合的工具类 Collections工具类
*/
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(10);
arrayList.add(20);
arrayList.add(30);
arrayList.add(140);
//根据指定顺序进行排序
/* arrayList.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1-o2;
}
});*/
Collections.sort(arrayList);
// //根据指定顺序进行排序
Collections.sort(arrayList, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1-02;
}
});
/*
最值的方法
*/
Integer max = Collections.max(arrayList);
System.out.println(max);
Integer min = Collections.min(arrayList);
System.out.println(min);
System.out.println(arrayList);
//二分查找 前提元素有序
Collections.sort(arrayList);
int i = Collections.binarySearch(arrayList, 10);
System.out.println(i);
//打乱
Collections.shuffle(arrayList);
System.out.println(arrayList);
//反转
Collections.reverse(arrayList);
System.out.println(arrayList);
//随机置换
}
}
模拟斗地主洗牌和发牌并对牌进行排序
public class Test2 {
/*
实现斗地主 实现发牌,洗牌,看牌 排序
*/
public static void main(String[] args) {
ArrayList<Integer> pokerIndex = new ArrayList<>();
HashMap<Integer, String> poker = new HashMap<>();
//定义两个集合 存储花色和序号
String[] colors = {"♥", "♣", "♠", "♦"};
//定义一个数字数组
String[] numbers = {"2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3"};
//存储大小王
int index=0;
poker.put(index,"大王");
pokerIndex.add(index);
index++;
poker.put(index,"小王");
pokerIndex.add(index);
for (String number : numbers) {
for (String color : colors) {
index++;
poker.put(index,number+color);
pokerIndex.add(index);
}
}
//洗牌
Collections.shuffle(pokerIndex);
//发牌
ArrayList<Integer> users1 = new ArrayList<>();
ArrayList<Integer> users2 = new ArrayList<>();
ArrayList<Integer> users3 = new ArrayList<>();
ArrayList<Integer> dipai = new ArrayList<>();
for (int i = 0; i < pokerIndex.size(); i++) {
Integer integer = pokerIndex.get(i);
if (i>=51){
dipai.add(integer);
}else if (i%3==1){
users2.add(integer);
}else if (i%3==2){
users3.add(integer);
}else if (i%3==0){
users1.add(integer);
}
}
Collections.sort(users1);
Collections.sort(users2);
Collections.sort(users3);
Collections.sort(dipai);
lookPoker("玩家1",poker,users1);
lookPoker("玩家2",poker,users2);
lookPoker("玩家3",poker,users3);
lookPoker("玩家1",poker,dipai);
}
private static void lookPoker(String name,HashMap<Integer,String> hashMap,ArrayList<Integer> arrayList) {
System.out.print(name+" ");
for (Integer integer : arrayList) {
String s = hashMap.get(integer);
System.out.print(s+" ");
}
System.out.println();
}
}