Java集合-Map接口(key-value)键值对

本文围绕Java中Map接口展开,介绍其特点为以KV键值对存储,Key唯一、Value可重复且无序。详细阐述了常见实现类,如HashMap无序,LinkedHashMap有序,TreeMap按key自动排序,Hashtable线程安全但性能低且不允许null做key和value,还提及各实现类的存储结构、方法等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Map接口

Map接口的特点:①KV键值对方式存储②Key键唯一,Value允许重复③无序。

常见实现类

  •   HashMap:无序
  •   LinkedHashMap:有序
  •   TreeMap:按照key自动排序
  •   Hashtable:无序
  1. 线程安全,性能低
  2. 不允许使用null做key
  3.  不允许使用null做value 

 

1.HashMap类:

存储结构:哈希表 = 数组Node[ ] + 链表(红黑树)

扩容方法:resize()

扩容机制:原数组的2倍

特点:①Key唯一,不允许重复②Value允许重复③无序

HashMap:KV键值对集合,key唯一,value允许重复

put()方法 :  添加键值对,如果key不存在,则返回null;如果key存在,则保存新value,返回旧value

get()方法:根据key,获取value ,如果key存在,获取该元素的键值对的value值;如果不存在,则获取该元素的键值对的value值为null;如果返回的value为null,类型转换时,会发生空指针

HashMap

1.按照key,重新计算hash值(让新的哈希值冲突概率更低,更散列)

2.按照hash值,计算在数组中存储的下标位置

3.判断该下标位置是否存在元素

 3.1如果该位置没有保存元素,则直接存入当前键值对

 3.2如果该位置已经保存元素,则以链表方式,将当前键值对保存至链表尾部(尾插法)

 3.3如果链表长度大于8,

为了提供搜索效率(链表不利于搜索),

会将链表转换为红黑树(红黑树,有序的自平衡二叉树,可以进行二分查找)

注意

HashMap

 key唯一: 保存的过程中,判断key是否一致,如果key相同,则覆盖

 无序: 添加的顺序与存储的顺序不一致,输出时按照存储顺序

哈希值的计算:

package com.ztt.Demo02;

public class demo19 {
	public static void main(String[] args) {
		int hash = 6344634;//哈希值
		int n = 16;//数组的长度(要求必须的2的n次幂)
		
		int index1 = hash % n; //%算术运算符的计算性能差
		int index2 = (n-1)&hash;//位运算的计算性能高
		
		System.out.println("下标1:"+index1);
		System.out.println("下标2:" + index2);
	}

}

 运行结果:

下标1:10
下标2:10

package com.ztt.Demo02;

import java.util.Arrays;
import java.util.HashMap;
import java.util.TreeSet;

public class demo07 {
	public static void main(String[] args) {
		
		//单列集合
		TreeSet<String> set = new TreeSet<String>();set.add("x西安");
		set.addAll(Arrays.asList("A阿城","B北京","C长春" , "D大连", "E鄂尔多斯" , "A阿富汗"));
		System.out.println(set);
		// Map键值对集合
		//保存城市人口信息
		//key :城市名称
		// val : 人口数量
		HashMap<String, Integer> map=new HashMap<String, Integer>();
		map.put("X西安", 1100);
		
		HashMap<String, Integer> anotherMap=new HashMap<String, Integer>();
		anotherMap.put("B北京", 2500);
		anotherMap.put("C长春", 300);
		anotherMap.put("D大连", 1000);
		map.put("X西安", 1100);
		anotherMap.put("D大连", 1000);//key不允许重复
		map.put("E鄂尔多斯", 1000);//value允许重复
		
		System.out.println(map);

	}

}

运行结果:

[A阿城, A阿富汗, B北京, C长春, D大连, E鄂尔多斯, x西安]
{X西安=1100, E鄂尔多斯=1000}

put()与get()方法: 

package com.ztt.Demo02;

import java.util.HashMap;

public class demo08 {
	public static void main(String[] args) {
		// HashMap
		//KV键值对集合,key唯一,value允许重复
		HashMap<String, Integer> cityMap=new HashMap<String, Integer>();
		
		//put()方法:添加键值对
		//如果key不存在,则返回null
		System.out.println(cityMap.put("X西安", 1100));
		System.out.println(cityMap.put("B北京", 1100));
		System.out.println(cityMap.put("C长春", 1100));
		System.out.println(cityMap.put("D大连", 1100));
		
		//如果key存在,则保存新value,返回旧value
		System.out.println(cityMap.put("X西安", 1200));
		
		// get()方法:根据key,获取value
		// key存在
		int value1=cityMap.get("B北京");//Integer->int
		System.out.println("B北京==>"+value1);
		
		// key不存在
		Integer value2=cityMap.get("N南京");//Integer->int
		System.out.println("N南京==>"+value2);
		
		//如果返回的value为null,类型转换时,会发生空指针
		int value3=cityMap.get("N南京");//Integer->int
	}
	

}

运行结果:

null
null
null
null
1100
B北京==>1100
N南京==>null
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "java.util.HashMap.get(Object)" is null
	at com.ztt.Demo02.demo08.main(demo08.java:31)

遍历Map 

方式1:获取所有的key,然后按照每个key获取对应的value

方式2:获取所有的value

方式3:将每个KV键值对按照Entry类型的对象,统一获取

方式1:获取所有的key,然后按照每个key获取对应的value 

package com.ztt.Demo02;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

public class demo09 {
	public static void main(String[] args) {
		//歌手分类
		HashMap<String, String[]> map=new HashMap<String, String[]>();
		
		map.put("华语", new String[] { "林俊杰", "陈奕迅", "邓紫棋", "薛之谦", "汪苏泷", "李荣浩" });
		map.put("欧美", new String[] { "贾斯丁比伯", "威肯", "艾兰沃克", "德雷克" });
		map.put("乐队", new String[] { "魔力红", "烟鬼组合", "共和时代", "辅音组合", "Linkin Park", "Westlife" });
		
		//遍历Map
		//方式1:获取所有的key,然后按照每个key获取对应的value
		Set<String> keys=map.keySet();//获取map中所有的key
		
		System.out.println("所有的key:"+keys);
		System.out.println("按照每个key,获取每个对应的value");
		
		Iterator<String> it=keys.iterator();
		while(it.hasNext()) {
			String key=it.next();//获取每个key
			String[] val=map.get(key);//按照每个key获取对应的value
			System.out.printf("%s--->%s\n",key,Arrays.toString(val));
			
			//根据key,获取value(数组)
//			String[]array = map.get("乐队");
//			for ( String name : array) {
//			System.out.println( name ) ;
//			}
		}
	}

}

运行结果:

所有的key:[华语, 乐队, 欧美]
按照每个key,获取每个对应的value
华语--->[林俊杰, 陈奕迅, 邓紫棋, 薛之谦, 汪苏泷, 李荣浩]
乐队--->[魔力红, 烟鬼组合, 共和时代, 辅音组合, Linkin Park, Westlife]
欧美--->[贾斯丁比伯, 威肯, 艾兰沃克, 德雷克]

方式2:获取所有的value 

package com.ztt.Demo02;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Set;

public class demo10 {
	public static void main(String[] args) {
		//歌手分类
		HashMap<String, String[]> map=new HashMap<String, String[]>();
		
		map.put("华语", new String[] { "林俊杰", "陈奕迅", "邓紫棋", "薛之谦", "汪苏泷", "李荣浩" });
		map.put("欧美", new String[] { "贾斯丁比伯", "威肯", "艾兰沃克", "德雷克" });
		map.put("乐队", new String[] { "魔力红", "烟鬼组合", "共和时代", "辅音组合", "Linkin Park", "Westlife" });
		
		//遍历map
		//方式2:获取所有的value
		Collection<String[]> values=map.values();
		for(String[] array:values) {
			System.out.println(Arrays.toString(array));
		}
				
	}

}

运行结果:

[林俊杰, 陈奕迅, 邓紫棋, 薛之谦, 汪苏泷, 李荣浩]
[魔力红, 烟鬼组合, 共和时代, 辅音组合, Linkin Park, Westlife]
[贾斯丁比伯, 威肯, 艾兰沃克, 德雷克]

 方式3:将每个KV键值对按照Entry类型的对象,统一获取

package com.ztt.Demo02;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;

public class demo11 {
	public static void main(String[] args) {
		//歌手分类
		HashMap<String, String[]> map=new HashMap<String, String[]>();
		
		map.put("华语", new String[] { "林俊杰", "陈奕迅", "邓紫棋", "薛之谦", "汪苏泷", "李荣浩" });
		map.put("欧美", new String[] { "贾斯丁比伯", "威肯", "艾兰沃克", "德雷克" });
		map.put("乐队", new String[] { "魔力红", "烟鬼组合", "共和时代", "辅音组合", "Linkin Park", "Westlife" });
		
		//遍历map
		//方式3:将每个KV键值对按照Entry类型的对象,统一获取
		Set<Entry<String,String[]>> entrys=map.entrySet();
		for(Entry<String,String[]> keyValue:entrys) {
			System.out.printf("%s--->%s\n",keyValue.getKey(),Arrays.toString(keyValue.getValue()));
		}
	}
}

运行结果:

华语--->[林俊杰, 陈奕迅, 邓紫棋, 薛之谦, 汪苏泷, 李荣浩]
乐队--->[魔力红, 烟鬼组合, 共和时代, 辅音组合, Linkin Park, Westlife]
欧美--->[贾斯丁比伯, 威肯, 艾兰沃克, 德雷克]
  • 判断key是否存在:containsKey()方法
  • 根据key获取value,如果key不存在,则返回default默认值:getOrDefault()方法
  • 根据key,删除KV键值对:remove()方法
  • 获取键值对的数量:size()方法
package com.ztt.Demo02;

import java.util.Arrays;
import java.util.HashMap;

public class demo12 {
	public static void main(String[] args) {
		//歌手分类
		HashMap<String, String[]> map=new HashMap<String, String[]>();
		
		map.put("华语", new String[] { "林俊杰", "陈奕迅", "邓紫棋", "薛之谦", "汪苏泷", "李荣浩" });
		map.put("欧美", new String[] { "贾斯丁比伯", "威肯", "艾兰沃克", "德雷克" });
		map.put("乐队", new String[] { "魔力红", "烟鬼组合", "共和时代", "辅音组合", "Linkin Park", "Westlife" });
		
		//判断key是否存在
		boolean isContains = map.containsKey("日韩");
		System.out.println(isContains);
		
		//根据key获取value,如果key不存在,则返回default默认值
		String[] value = map.getOrDefault("日韩", new String[] {});
		System.out.println(Arrays.toString(value));
		
		//根据key,删除KV键值对
		map.remove("欧美");
		System.out.println(map);
		
		//获取键值对的数量
		int size = map.size();
		System.out.println(size);
	}

}

运行结果:

false
[]
{华语=[Ljava.lang.String;@626b2d4a, 乐队=[Ljava.lang.String;@5e91993f}
2
2.LinkedHashMap类:

存储结构:数组+链表+红黑树,,多维护了一个双向链表,记录顺序

特点:①Key唯一,不允许重复②Value允许重复③有序④LinkedHashMap是HashMap的子类

package com.ztt.Demo02;

import java.util.HashMap;
import java.util.LinkedHashMap;

public class demo14 {
	public static void main(String[] args) {
		//统计每个字符出现的次数
		String str="aabbbbsssddffghjjkllkjhgfdsaqwertyuiozxcvcxzzxccvvoozzz";
		//无序
		//HashMap<String, Integer> map=new HashMap<String, Integer>();
		
		//有序
		LinkedHashMap<String, Integer> map=new LinkedHashMap<String, Integer>();
		
		for(int i=0;i<str.length();i++) {
			String key=str.substring(i,i+1);
			//判断key是否存在
			if(map.containsKey(key)) {
				//该字符(key)存在
				map.put(key, map.get(key)+1);
			}else {
				//该字符(key)不存在
				map.put(key,1);//默认次数为1
			}
		}
		System.out.println(map);
		
		
	}

}

运行结果:

{a=3, b=4, s=4, d=3, f=3, g=2, h=2, j=3, k=2, l=2, q=1, w=1, e=1, r=1, t=1, y=1, u=1, i=1, o=3, z=6, x=3, c=4, v=3}
3.TreeMap类:

特点:①Key唯一,不允许重复②Value允许重复③按照Key自动排序④AbstractMap的子类

存储结构:树中的每个节点均是Entry内部类对象(红黑树)有序的自平衡二叉树

例:按照key自动排序,通过key进行比较后排序!!!

package com.ztt.Demo02;

import java.util.Map.Entry;
import java.util.Comparator;
import java.util.TreeMap;

public class demo15 {
	public static void main(String[] args) {
		
		// HashMap:无序,按照key计算保存位置
		// HashMap<String,string> map = new HashMap<String,string>();
		
		// TreeMap:按照key自动排序,通过key进行比较后排序
		TreeMap<String, String> map=new TreeMap<String, String>(new Comparator<String>() {

			@Override
			public int compare(String o1, String o2) {
				int n1=Integer.parseInt(o1.substring(2));
				int n2=Integer.parseInt(o2.substring(2));
				
				return n1-n2;
			}
			
});
		map.put("SN201", "A1");
		map.put("SN101", "A2");
		map.put("SN111", "A3");
		map.put("SN191", "A4");
		map.put("SN100", "A5");
		map.put("SN110", "A6");
		map.put("SN1231", "A7");
		map.put("SN2001", "A8");
		map.put("SN2024", "A9");
		
		for(Entry<String, String> entry:map.entrySet()) {
			System.out.println(entry.getKey()+":"+entry.getValue());
		}
	}

}

运行结果:

SN100:A5
SN101:A2
SN110:A6
SN111:A3
SN191:A4
SN201:A1
SN1231:A7
SN2001:A8
SN2024:A9
4.Hashtable类

特点:①Key唯一,不允许重复②Value允许重复③key 和 value不允许为空,如果为null,则抛出NullPointerExceptino④线程安全,使用synchronized加锁,性能较差

存储结构:数组+链表

  • 不允许使用null做key
  • 不允许使用null做value
package com.ztt.Demo02;

import java.util.HashMap;
import java.util.Hashtable;

public class demo16 {
	public static void main(String[] args) {
		
		HashMap<String, String> map=new HashMap<String, String>();
		map.put(null, "巴黎世家");//不允许使用null做key
		map.put("AAA", null);//允许使用null做value
		System.out.println(map);
		
		Hashtable<String, String> table=new Hashtable<String, String>();
		table.put(null, "巴黎世家");//不允许使用null做key
		table.put("AAA", null);//不允许使用null做value
		System.out.println(table);
		}
	
}

运行结果:

{null=巴黎世家, AAA=null}
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Object.hashCode()" because "key" is null
	at java.base/java.util.Hashtable.put(Hashtable.java:481)
	at com.ztt.Demo02.demo16.main(demo16.java:15)
package com.ztt.Demo02;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

public class demo20 {
    public static void main(String[] args) {
        //原始数据
        HashMap<String, Integer> voteMap = new HashMap<>();
        voteMap.put("武松", 127);
        voteMap.put("武松", 127);
        voteMap.put("晁盖", 181);
        voteMap.put("燕青", 197);
        voteMap.put("卢梭义", 100);
        voteMap.put("宋江", 69);
        voteMap.put("霸天虎", 149); 

        //按照票数排序输出
        
        ArrayList<Entry<String,Integer>> list=new ArrayList<Entry<String,Integer>>();
        list.addAll(voteMap.entrySet());
        
        //排序
        list.sort(new Comparator<Entry<String,Integer>>() {

			@Override
			public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
//				if(o1.getValue()>o2.getValue()) {
//					return 1;
//				}else if(o1.getValue()<o2.getValue()){
//					return -1;
//				}
//				return 0;
				return o2.getValue()-o1.getValue();
			}
        	
		});
        
        for(Entry<String,Integer> vote:list) {
        	System.out.printf("%s的票数是:%s票",vote.getKey(),vote.getValue());
        }
      
    }
}

运行结果:

燕青的票数是:197票晁盖的票数是:181票霸天虎的票数是:149票武松的票数是:127票卢梭义的票数是:100票宋江的票数是:69票

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值