Map集合
java.util.Map
Map集合特点:
1.Map集合是一个双列集合,一个元素包含两个值(一个key,一个value)
2.Map集合中,key和value的数据类型可以相同,也可以不同
3。Map集合中的元素,key时不允许重复,value是可以重复的
4.Map集合中的元素,key和value是一一对应的
Map集合的两个子类集合:
HashMap
Java.util.HashMap
HashMap集合的特点:
1.HashMap集合底层是哈希表:查询的速度特别快
jdk1.8之前:数组+单向链表
jdk1.8之后:数组+单向链表/红黑树(链表的长度超过8):提高查询速度
2.hashMap集合是一个无序集合,存储元素和取出元素的顺序可能不一致
LinkedHashMap
java.util.LinkedHashMap
LinkedHashMap集合的特点:
1.LinkedHashMap集合的底层是哈希表+链表(保证迭代的顺序)
2.LinkedHashMap集合是一个有序的集合,存储元素和取出元素的顺序是一致的
Map接口中常用的方法:
V put(K key, V value);//将key与之对应的value,放入Map集合中
返回值:
存储键值对的时候,key不重复,返回值V是null
存储键值对的时候,key重复,会用新value来替换已经存储的value,并返回这个已经存储的value
V remove(Object key);//删除key所对应的value,并返回value
返回值:
key存在,返回删除的value
key不存在,返回null
V get(Object key);//获取key所对应的value
返回值:
key存在,返回对应的value
key不存在,返回null
boolean containsKey(Object key);//Map集合中是否包含指定的key,有true,无false
package mymap;
import java.util.HashMap;
import java.util.Map;
//测试Map接口常用方法
public class TestMap01 {
public static void main(String[] args) {
Map hashMap = new HashMap<>();
hashMap.put("小明",12);
hashMap.put("小红",5);
hashMap.put("小刚",16);
hashMap.put("小王",22);
hashMap.put("小张",32);
System.out.println(hashMap);//{小刚=16, 小明=12, 小王=22, 小红=5, 小张=32}
Integer b1 = hashMap.remove("小张");
System.out.println(b1);//32
Integer b2 = hashMap.remove("老李");
System.out.println(b2);//null
System.out.println(hashMap);//{小刚=16, 小明=12, 小王=22, 小红=5}
Integer c1 = hashMap.get("小明");
System.out.println(c1);//12
Integer c2 = hashMap.get("老刘");
System.out.println(c2);//null
boolean d1 = hashMap.containsKey("小刚");
System.out.println(d1);//true
boolean d2 = hashMap.containsKey("秦始皇");
System.out.println(d2);//false
}
}
Map集合的第一种遍历方式:通过键找值的方式
Map集合的方法:
Set keySet();//将Map集合中所有的key存储到set集合中,并返回
实现步骤:
1.使用Map集合中的方法keySet(),将Map集合中所有的key取出来,存储到一个set集合里面
2.遍历set集合,获取Map集合中的每一个key
3.通过Map集合的方法get(key),通过key找到value
Map hashMap = new HashMap<>();
hashMap.put("小明",12);
hashMap.put("小红",5);
hashMap.put("小刚",16);
hashMap.put("小王",22);
hashMap.put("小张",32);
/* Set set = hashMap.keySet();
for (String s : set) {
System.out.print(hashMap.get(s)+"\t");
}
*/
//简化版
for (String s : hashMap.keySet()) {
System.out.print(hashMap.get(s)+"\t");
}
Map集合的第二种遍历方式:使用Entry对象遍历
Map集合中的方法:
Set> entrySet();//将Map集合中所有的键值对对象Entry,放入set集合中,并返回
实现步骤:
1.使用Map集合中的方法entrySet(),把Map集合中多个Entry对象取出来,存储到一个set集合中
2.遍历set集合,获取每一个Entry对象
3.使用Entry对象的方法getKey()和getValue()获取键与值
Map hashMap = new HashMap<>();
hashMap.put("小明",12);
hashMap.put("小红",5);
hashMap.put("小刚",16);
hashMap.put("小王",22);
hashMap.put("小张",32);
/*Set> entries = hashMap.entrySet();
for (Map.Entry entry : entries) {
System.out.print(entry.getKey()+"="+entry.getValue()+"\t");
}*/
//简化版
for (Map.Entry entry : hashMap.entrySet()) {
System.out.print(entry.getKey()+"="+entry.getValue()+"\t");
}
HashMap存储自定义类型键值
Map集合保证key是唯一的:
作为key的元素,必须重写hashCode方法和equal方法,以保证key的唯一
package mymap;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
//用hashmap存储自定义类型
public class TestHashMap01 {
public static void main(String[] args) {
HashMap hashMap = new HashMap<>();
hashMap.put(new Person("小张",23),"上海");
hashMap.put(new Person("小王",33),"北京");
hashMap.put(new Person("小刘",43),"广州");
hashMap.put(new Person("小张",23),"上海");//和第一个添加的key相同
//Map集合保证key是唯一的, 作为key的元素,必须重写hashcode方法和equals方法,以保证key的唯一
//若不重写,输出为Person{name='小刘', age=43}-->广州Person{name='小王', age=33}-->北京Person{name='小张', age=23}-->上海Person{name='小张', age=23}-->上海
//Map里面有两个key相同,不允许
for (Map.Entry entry : hashMap.entrySet()) {
Person key = entry.getKey();
String value = entry.getValue();
//重写hashcode方法和equals方法后
System.out.print(key+"-->"+value);//Person{name='小刘', age=43}-->广州Person{name='小王', age=33}-->北京Person{name='小张', age=23}-->上海
}
}
}
class Person{
private String name;
private int age;
public Person() {
}
public Person(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 "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//Map集合保证key是唯一的, 作为key的元素,必须重写hashcode方法和equals方法,以保证key的唯一
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
LinkedHashMap集合
java.util.LinkedHashMap
Map接口的哈希表和链表列表的实现,具有可预知的迭代性
底层原理:
哈希表+链表(记录元素的顺序)
package mymap;
import java.util.LinkedHashMap;
public class TestLinkedHashMap01 {
public static void main(String[] args) {
LinkedHashMap linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put(1, "渐渐");
linkedHashMap.put(2, "哈哈");
linkedHashMap.put(3, "好好");
linkedHashMap.put(1, "微微");//Integer类中重写了hashcode方法和equals方法,Map的key唯一,重写,将第一个覆盖了
for (Integer key : linkedHashMap.keySet()) {
System.out.print(key + "-->" + linkedHashMap.get(key) + "\t");//1-->微微 2-->哈哈 3-->好好 ,按添加顺序,LinkedHashMap是有顺序的,存取顺序相同
}
}
}
HashTable集合
java.util.HashTable
HashTable:底层是一个哈希表,是一个线程安全集合,是单线程集合,速度慢
HashMap:底层是一个哈希表,是一个线程不安全集合,是多线程集合,速度快
hashMap集合(之前学的所有集合):可以存储null值,null键
HashTable集合,不能存储null键,null值
HashTable和vector集合一样,在jdk1.2版本之后被更先进的集合所替代(HashMap,arrayList)
HashTable的子类properties依然活跃在历史的舞台
properties集合是一个唯一和IO流相结合的集合
练习:
package mymap;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
//获取用户输入字符串中每个字符出现的次数
/*思路:
* 1.从输入台中获取字符串,转化为字符数组
* 2.创建一个Map集合,key代表字符,value代表次数
* 3.遍历字符数组,判断Map集合中key是否有该字符,有value+1,无往Map中添加
* 4.遍历Map集合,输出key和value*/
public class Practice01 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个英文字符:");
String str = scanner.nextLine();
char[] chars = str.toCharArray();
HashMap hashMap = new HashMap<>();
for (char c :chars){
int value = 0;
if (hashMap.containsKey(c)){
value = hashMap.get(c);
value++;
}else {
value = 1;
}
hashMap.put(c,value);
}
for (Map.Entry entry : hashMap.entrySet()) {
System.out.println(entry.getKey()+"出现的次数:"+entry.getValue());
}
}
}
package mymap;
import java.util.*;
//模拟斗地主,洗牌发牌过程,在玩家手中牌要有顺序
//自己写的版本
public class Practice02 {
public static void main(String[] args) {
//54张扑克牌
LinkedHashMap pokers = new LinkedHashMap<>();
//存储大小王
pokers.put(0,"JOKER");
pokers.put(1,"joker");
//存储其他52张牌
ArrayList colors = new ArrayList<>();
Collections.addAll(colors,"♠","♥","♦","♣");
ArrayList nums = new ArrayList<>();
Collections.addAll(nums,"2","A","K","Q","J","10","9","8","7","6","5","4","3");
int i=2;
for (String num : nums) {
for (String color : colors) {
pokers.put(i++,color+num);
}
}
System.out.println(pokers);
//将pokers Map集合中key存储到List集合中
ArrayList keyList = new ArrayList<>();
for (Map.Entry entry : pokers.entrySet()) {
keyList.add(entry.getKey());
}
System.out.println(keyList);
//打乱key顺序,打乱牌顺序
Collections.shuffle(keyList);
System.out.println(keyList);
//发牌
ArrayList p1 = new ArrayList<>();
ArrayList p2 = new ArrayList<>();
ArrayList p3 = new ArrayList<>();
ArrayList bottom = new ArrayList<>();
ArrayList[] arr = {p1,p2,p3,bottom};
for (int i1 = 0; i1 < keyList.size(); i1++) {
if (i1 >= 51) {
bottom.add(pokers.get(keyList.get(i1)));
}else if (i1 % 3 == 0){
p1.add(pokers.get(keyList.get(i1)));
}else if (i1 % 3 == 1){
p2.add(pokers.get(keyList.get(i1)));
}else if (i1 % 3 == 2){
p3.add(pokers.get(keyList.get(i1)));
}
}
//对每个人手中的牌进行排序
for (ArrayList arrayList : arr) {
Collections.sort(arrayList, new Comparator() {
@Override
public int compare(String o1, String o2) {
int key1 = 0;
int key2 = 0;
for (Map.Entry entry : pokers.entrySet()) {
if (entry.getValue().equals(o1) ){
key1 = entry.getKey();
}
if (entry.getValue().equals(o2)){
key2 = entry.getKey();
}
}
return key1 - key2;
}
});
}
//查看每一个人手中的牌,和底牌
for (int i1 = 0; i1 < arr.length; i1++) {
if (i1 == arr.length - 1){
System.out.println("底牌为:");
}else {
System.out.println("第"+(i1+1)+"位玩家的牌为:");
}
for (int i2 = 0; i2 < arr[i1].size(); i2++) {
System.out.print(arr[i1].get(i2)+"\t");
}
System.out.println();
}
}
}
package mymap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
//老师写的版本
public class Practice03 {
public static void main(String[] args) {
//存储54张牌,和54张牌索引
HashMap pokers = new HashMap<>();
ArrayList pokersIndex = new ArrayList<>();
//存储大小王
int index = 0;
pokers.put(index,"JOKER");
pokersIndex.add(index);
index++;
pokers.put(index,"joker");
pokersIndex.add(index);
index++;
//存储其他52张牌
ArrayList colors = new ArrayList<>();
Collections.addAll(colors,"♠","♥","♦","♣");
ArrayList nums = new ArrayList<>();
Collections.addAll(nums,"2","A","K","Q","J","10","9","8","7","6","5","4","3");
for (String num : nums) {
for (String color : colors) {
pokers.put(index,color+num);
pokersIndex.add(index);
index++;
}
}
System.out.println(pokers);
System.out.println(pokersIndex);
//洗牌
Collections.shuffle(pokersIndex);
System.out.println(pokersIndex);
//发牌
ArrayList p1 = new ArrayList<>();
ArrayList p2 = new ArrayList<>();
ArrayList p3 = new ArrayList<>();
ArrayList bottom = new ArrayList<>();
for (int i = 0; i < pokersIndex.size(); i++) {
if (i >= 51) {
bottom.add(pokersIndex.get(i));
}else if (i % 3 == 0) {
p1.add(pokersIndex.get(i));
}else if (i % 3 == 1) {
p2.add(pokersIndex.get(i));
}else if (i % 3 == 2) {
p3.add(pokersIndex.get(i));
}
}
//对每个人和底牌进行排序
Collections.sort(p1);
Collections.sort(p2);
Collections.sort(p3);
Collections.sort(bottom);
//查看每个人手中的牌和底牌
ArrayList[] arr = {p1,p2,p3,bottom};
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1){
System.out.println("底牌为:");
}else {
System.out.println("第"+(i+1)+"位玩家的牌为:");
}
for (int i1 = 0; i1 < arr[i].size(); i1++) {
System.out.print(pokers.get(arr[i].get(i1))+"\t");
}
System.out.println();
}
}
}
JDK9的新特性
List接口,Set接口,Map接口:里面增加了一个静态方法of,可以给集合一次性添加多个元素
static list of (E...elements)
使用前提:
当集合中存储的元素个数已经确定了,不再改变时使用
注意:
1.of方法只适用于List接口,Set接口,Map接口,不适应于接口的实现类
2.of方法的返回值是一个不可改变的集合,集合不能使用add,put方法添加元素,会抛出异常
3.set接口和map接口在调用of方法的时候,不能有重复的元素,否则报错