java第18天 TreeMap HasHMap

一.map

介绍:

map是键值对集合

<key,value>

key是唯一的,无序的,value是不唯一的 无序的

list:有序 不唯一

set:无序 唯一

sortedSet:有序 唯一【不如set】

所以取出value的话是单值集合,以上没有匹配的 那就用最大单值集合【Collection】

取出key的话是单值集合【唯一 无序】,上述只有set符合,所以用【Set】

二.map常用方法

1.添加元素put

		Map<String,Integer> map = new HashMap<String,Integer>();
        map.put("张三",25);

合并集合是 putAll(集合);

2.通过主键获取值 map.get(key)

Integer age=map.get("张三");

3.判断是否为空 isEmpty()

4.清空所有映射关系 map.clear()

5.删除元素 map.remove(key);

6.查看是否有数值,查看是否包含某主键

map.containsValue(值的泛型);

map.containsKey(主键的泛型);

以上方法的练习

import java.util.*;
public class Exec1{
	public static void main(String[] args){
		Map<String,Integer> map = new HashMap<String,Integer>();
		map.put("[魏] 郭奉孝",38);
		map.put("[魏] 夏侯妙才",80);
		map.put("[蜀] 诸葛孔明",40);
		map.put("[蜀] 赵子龙",98);
		map.put("[吴] 大乔",6);
		map.put("[群] 吕奉先",100);
		map.put("[吴] 鲁子敬",39);

		//1 请问我们总共收录了多少个英雄的信息?
		//System.out.println();
		System.out.println(map.size()+"个英雄的信息");
		//2 请问 其中有没有武力值是100的?
		System.out.println("有没有武力值是100的:"+map.containsValue(100));
		//3 请问 吴国的大乔有没有来啊?
		System.out.println("吴国的大乔有没有来"+map.containsKey("[吴] 大乔"));
		//4 请问 蜀国大将赵子龙武力值是多少?
		System.out.println("蜀国大将赵子龙武力值"+map.get("[蜀] 赵子龙"));
    }}

三.map的遍历

map没有iterator的方法,并且也没有下标,所以利用它的key和值

key是唯一的,无序的,value是不唯一的 无序的
list:有序 不唯一
set:无序 唯一
sortedSet:有序 唯一【不如set】

所以取出value的话是单值集合,以上没有匹配的 那就用最大单值集合【Collection】
取出key的话是单值集合【唯一 无序】,上述只有set符合,所以用【Set】

关于值的使用

        //请问 所有英雄的平均武力值是多少?
        int sum=0;
		Collection<Integer> cs=map.values();
		for(Integer ii:cs){
			sum+=ii;
		}
		System.out.println("所有英雄的平均武力值:"+sum/map.size());

关于key的使用

Set<String> cc=map.keySet();
		int count=0;
		int wujiang=0;
		for(String ss:cc){
			if(ss.split(" ")[1].length()>=4){
				count++;
			}
			if(ss.split(" ")[0].contains("吴")){
				wujiang++;
			}
		}
		System.out.println(count+"个英雄名字像鬼子");

		//请问 总共有多少个吴国的武将?
		System.out.println(wujiang+"个吴国的武将");

Map集合的遍历方式

通过Map集合得到所有的主键视图:
Set<主键> set = map.keySet();
遍历集合得到主键:x
通过主键得到值对象:map.get(x)
通过Map集合得到所有的值视图:
Collection<值> cs = map.values();
遍历集合得到值对象:x
通过Map集合得到每条记录[主键+值]
Set<Map.Entry<主键,值>> set = map.entrySet();
遍历集合得到每对信息:Map.Entry<K,V> x[主键+值]
通过每条信息获得主键:x.getKey()
通过每条信息获得值:x.getValue()
通过每条信息修改值:x.setValue(值)

四.获取主键和值

主键和值 就是【无序,唯一】 可以使用Set的集合

Set<Map.Entry<String,Integer>> set=map.entrySet();

String name=info.getKey();//获取主键

Integer power=info.getValue();//获取值

info.setValue(power-10);//值减少10

Set<Map.Entry<String,Integer>> set=map.entrySet();
//相当于获取了所有的一条条数据的集合 然后遍历可以
for(Map.Entry<String,Integer> info:set){
    String name=info.getKey();//获取主键
    Integer power=info.getValue();//获取值
    修改值的话
    info.setValue(power-10);//值减少10
}

有关的练习:

//请计算魏国武将的平均武力值~
		//魏国总武力值 / 魏国总人数
		int sum01=0;
		int count01=0;
		Set<Map.Entry<String,Integer>> set=map.entrySet();//拿出的是视图

		for(Map.Entry<String,Integer> info:set){//获取的视图单个的 改变一个map也要改变
			String name=info.getKey();
			Integer power=info.getValue();
			if(name.contains("[魏]")){
				sum01+=power;
				count01++;
			}
		}
		System.out.println("魏国武将的平均武力值:"+sum01/count01);


		//蜀国大旱  所有的蜀国将军武力值上涨5个点      】

		Set<Map.Entry<String,Integer>> set01=map.entrySet();

		for(Map.Entry<String,Integer> info:set01){
			String name=info.getKey();
			Integer power=info.getValue();
			if(name.contains("[蜀]")){
				info.setValue(power+5);
			}
		}
		System.out.println(map);

主键重复呢?

当添加重复主键时 将舍弃老的数据,存入新的数据

        String str = "张三,李四,张三,王五,李四,张三";
		//分别统计每个名字出现的次数
		// {}
		Map<String,Integer> map = new HashMap<>();
		// 名字=次数
		// 拿到每一个名字 name
		String[] data=str.split(",");
		//Integer count=0;
		for(String temp:data){
		
			map.put(temp,(map.containsKey(temp))?map.get(temp)+1:1);
		}
		System.out.println(map);

练习3

import java.util.*;
public class Exec3{
	public static void main(String[] args){
		HashMap<String,String> map = new HashMap<>();
		map.put("342423199808062065","汪漂亮");//女
		map.put("465435458657656633","赵笑笑");//男
		map.put("346573453456447720","王雪");//女
		map.put("34563475378564544X","叮叮当当");//女
		map.put("364563453573456475","欧阳阳阳");//男

		//得到主键:Set<主键> set = map.keySet();
		//得到值:Collection<值> cs = map.values();
		//得到主键+值:Set<Map.Entry<主键,值>> set = map.entrySet();

		//统计有多少个女生 【倒数第二位】16 keySet()
		Set<String> set=map.keySet();
		int count=0;
		for(String info:set){
			if(Integer.parseInt((info.charAt(16)+""))%2==0){
				count++;
			}
		}
		System.out.println("统计有多少个女生:"+count);
		//打印谁的名字里面出现叠字 values()
		Collection<String> cc=map.values();
		for(String info:cc){
			String[] temp=info.split("");
			for(int i=0;i<temp.length-1;i++){
				if(temp[i].equals(temp[i+1])){
					System.out.println(info);
					break;
				}
			}
		}

		//将身份证尾号是2065学生 姓名改成小X entrySet()
		Set<Map.Entry<String,String>> set01=map.entrySet();
		for(Map.Entry<String,String> info:set01){
			String id=info.getKey();
			String name=info.getValue();
			//endsWith
			if(id.substring(14).equals("2065")){

				info.setValue("小"+name.charAt(0));
			}

		}
		System.out.println(map);
	}
}

HashMAp底层逻辑:

HashMap 底层基于哈希表 默认分16个小组 每对元素[key=value]应该装进哪一个小组 
根据主键的哈希码值决定【key.hashCode() -> int】 
为了保证主键的唯一性 所以只要新来的一对元素装到某个小组之后 
如果发现该小组里面有元素的主键和新来的主键哈希码值一样 那么会触发 
== equals()比较

面试题:HashMap和Hashtable之间的区别?

1.同步特性不同:

Hashtable同一时间允许一个线程进行访问 效率较低 但是不会出现 并发错误

HashMap同一时间允许多个线程进行访问 效率较高 但是可能会出现 并发错误

jdk5.0开始 集合的工具类里面提供一个方法 将线程不安全的 HashMap变成线程安全的Map集合 于是Hashtable渐 渐被淘汰

Map xx = Collections.synchronizedMap(HashMap对象)

2.对null的容忍度不同

Hashtable无论是主键还是值 都不能传入null 否则触发空指针异常

HashMap无论是主键还是值都可以传入null 由于主键唯一 所以主键 只能输入一个null 值可以输入多个null

3.默认分组不同:

Hashtable默认分11个小组 程序员可以随意的指定

HashMap默认分16个小组 程序员可以随意的指定 但是最终一定会变 成2的n次方数

4.出现的版本不同:

Hashtable since jdk1.0

HashMap since jdk1.2

HashMap Hashtable ConcurrentHashMap之间的区别?

Hashtable为了保证安全性 同一时间只允许一个线程进入哈希表进行访问 一旦某个线程进入哈希表之后 将整个小组全部加锁 效率极低

HashMap为了保证高效性 里面所有的方法将不再加锁 在多线程的情况下可能会触发并发错误

ConcurrentHashMap采用锁分离机制 将锁的粒度降低 如果有一个线程进入哈希表之后 为了保证安全性和高效性 仅仅对该分组加锁 如果

新来的线程想要去没有加锁的小组 可以访问 如果新来的线程想要访问加锁的小组 需要等待

在多线程的情况下 HashMap不安全 有什么可以替代的方案?

ConcurrentHashMap

Collections.synchronizedMap(HashMap)

HashMap底层分组为什么一定是2的n次方数?

如果计算key=value应该去到哪一个小组

计算公式:

key.hashCode() % 分组组数 看余数

如果分组是2的n次方数

key.hashCode() & 分组组数-1

HashMap在jdk8.0前后的底层变化

HashMap底层基于哈希表实现的

jdk8.0之前 底层由数组 + 链表组成

数组:方便元素快速的定位应该去到哪一个小组

链表:方便组内的元素进行添加/删除操作

采用头插法【新来元素放在链表前面】

jdk8.0及之后 底层由数组 + 链表 + 二叉树组成

数组:方便元素快速的定位应该去到哪一个小组

链表:方便组内的元素进行添加/删除操作

如果链表长度 >= 8 由链表结构转换成二叉树结构

当二叉树的元素个数 <= 6 由二叉树变成链表

采用尾插法【新来元素放后面】

哈希算法规则

当我们想要往HashSet/HashMap集合中添加元素的时候

1:底层会通过主键 获得哈希码值:int h = key.hashCode();

2: 继续调用哈希算法对哈希码值进行优化:h ^ (h >>> 16)

3: 对最终的哈希码值 % 分组组数看余数

TreeMap 底层基于二叉树实现的 每次往集合里面添加一对信息应该被装进左子树 / 右子树 根据 主键决定 拿着新来的主键和遇到的老主键比较

compareTo()/compare()比较大小

大于0 新来的一对元素放在右边

等于0 主键不变 值替换

小于0 新来的一对元素放在左边

相关推荐
xlsw_1 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹2 小时前
基于java的改良版超级玛丽小游戏
java
梧桐树04292 小时前
python常用内建模块:collections
python
Dream_Snowar2 小时前
速通Python 第三节
开发语言·python
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭2 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫3 小时前
泛型(2)
java
超爱吃士力架3 小时前
邀请逻辑
java·linux·后端
南宫生3 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石3 小时前
12/21java基础
java
李小白663 小时前
Spring MVC(上)
java·spring·mvc