Java-集合(5)
创始人
2024-05-26 06:56:18
0

Map接口

JDK8

Map接口实现子类的特点

  1. Map和Collection是并列关系,Map用于保存具有映射关系的数据:Key-Value
  2. Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
  3. Map中的key不允许重复,原因和HashSet一样
  4. Map中的value可以重复
  5. Map的key可以为null,value也可以为null,但是key只能有一个null,value可以有多个null只要key不同就行
  6. 常用String类为Map的key
  7. key和value之间存在单向一对一关系,即通过key找到对应的value。可以理解为key相当于身份证号,value是对应的人,人可以重复名字样貌等,但是身份证不能重复。
  8. 当加入一个重复的key和不重复的value时,相当于替换

测试:

public class test1 {public static void main(String[] args) {Map map = new HashMap();map.put("nbo1","张三");map.put("nbo2","李四");map.put("nbo3","王五");map.put("nbo1","李向");System.out.println(map);}
}

运行结果:
{nbo2=李四, nbo1=李向, nbo3=王五}

在之前Collection接口实现集合类,都是使用key来直接保存存储的数据。而Map接口实现集合类会使用key和value两个相互映射来保存数据,key可以看作是一个序号或者身份证号,value才是真正保存的数据

理解:Map存放的key-value是放在一个Node中的,又因为Node实现了Entry接口,所以也说一对k-v也是一个Entry**

在这里插入图片描述
我们知道当使用Map实现集合类存放了一个元素时,会有key和value,也就是键和值,键key可以看作是一个序号,值valuie可以看作是内容,一个序号对应一个内容,而这两个东西是存放在一个Node节点中的。但是因为Map不是Collection接口,Map没有实现iterator接口,所以要遍历不是很方便。因此在添加元素时除了会保存到table数组时,还会做一件事情就是保存到一个EntrySet集合中,EntrySet集合中的保存类型不是Node类型而是Entry类型。
但是这里的意思不是说把table中的数组都复制一份到EntrySet集合中,而是单纯的引用,也就是把EntrySet中的一个个Entry指向的还是table中的一个个Node。而为什么要做这么一件事呢,这是因为在EntrySet集合中保存的key是Set接口类型的value是Collection接口类型的,当然实际运行类型还是Node,只不过这样就可以使用迭代器了。

public class test1 {public static void main(String[] args) {Map map = new HashMap();map.put("nbo1","张三");map.put("nbo2","李四");map.put("nbo3","王五");map.put("nbo1","李向");Set set = map.entrySet();for (Object obj:set) {Map.Entry entry = (Map.Entry) obj;System.out.println(entry.getClass());System.out.println(entry.getKey()+"-"+entry.getValue());}}
}

运行结果:
class java.util.HashMapNodenbo2−李四classjava.util.HashMapNode nbo2-李四 class java.util.HashMapNodenbo2−李四classjava.util.HashMapNode
nbo1-李向
class java.util.HashMap$Node
nbo3-王五

Map接口实现类的常用方法

口语说法:key:键 ———— value:值

  1. put(key,value);添加,当再次添加同一个键,但是值不同时,会对值进行替换
  2. remove(key);根据键删除这对键和值
  3. get(key);根据键获取值
  4. size();获取当前集合的元素个数
  5. isEmpty():判断当前集合元素个数是否为0
  6. containsKey(key);查找传入的键是否存在
  7. clear:清除集合所有元素,归0

使用演示

public class test2 {public static void main(String[] args) {Map map = new HashMap();//        1. put(key,value);添加,当再次添加同一个键,但是值不同时,会对值进行替换map.put("no1","李青");map.put("no2","绿意");map.put("no1","李青");System.out.println(map);
//        2. remove(key);根据键删除这对键和值map.remove("no1");System.out.println(map);
//        3. get(key);根据键获取值System.out.println(map.get("no2"));
//        4. size();获取当前集合的元素个数System.out.println(map.size());
//        5. isEmpty():判断当前集合元素个数是否为0System.out.println(map.isEmpty());
//        6. containsKey(key);查找传入的键是否存在System.out.println(map.containsKey("no2"));
//        7. clear:清除集合所有元素,归0map.clear();System.out.println(map);}
}

运行结果:
{no2=绿意, no1=李青}
{no2=绿意}
绿意
1
false
true
{}

Map接口实现类的六大遍历方式

上面了解到了map存入的数据还会有一个EntrySet集合指向table数组中的数据,所以遍历也是围绕这个来操作
Map实现接口可以分为三大类:每类有两种方式
1.获取键key,再通过键来获取值value
2.直接获取值value,但是无法通过值value获取key,所以只能输出value
3.通过EntrySet,同时获取到键和值

遍历用到的方法

  1. KeySet:获取所有键
  2. entrySet:获取所有键和值k-v
  3. values:获取所有值

演示:

public class test3 {public static void main(String[] args) {Map map = new HashMap();map.put("no1","淘宝");map.put("no2","天猫");map.put("no3","京东");//第一类:获取所有键,再通过get方法获取值。//第一种方式:获取键后使用增强forSystem.out.println("第一种");Set set = map.keySet();for (Object key:set) {System.out.println(key+"-"+map.get(key));}System.out.println("第二种");//第二种方式:获取键后,使用迭代器Iterator iterator = set.iterator();while (iterator.hasNext()) {Object next =  iterator.next();System.out.println(next+"-"+map.get(next));}//第二类:获取所有值//第三种方式:增强for,直接输出valueSystem.out.println("第三种");Collection value = map.values();for (Object o: value) {System.out.println(o);}//第四种:使用迭代器直接输出System.out.println("第四种");Iterator iterator2 = value.iterator();while (iterator2.hasNext()) {Object next =  iterator2.next();System.out.println(next);}//第三类:获取所有键和值,再向下转型成Entry,使用它的getKey和getValue方法//第五种:获取所有键和值,增强for操作System.out.println("第五种");Set entrySet = map.entrySet();for (Object e:entrySet) {Map.Entry entry = (Map.Entry) e;System.out.println(entry.getKey()+"-"+entry.getValue());}//第六种:迭代器操作System.out.println("第六种");Iterator iterator1 = entrySet.iterator();while (iterator1.hasNext()) {Object next =  iterator1.next();Map.Entry entry = (Map.Entry) next;System.out.println(entry.getKey()+"-"+entry.getValue());}}
}

运行结果:
第一种
no2-天猫
no1-淘宝
no3-京东
第二种
no2-天猫
no1-淘宝
no3-京东
第三种
天猫
淘宝
京东
第四种
天猫
淘宝
京东
第五种
no2-天猫
no1-淘宝
no3-京东
第六种
no2-天猫
no1-淘宝
no3-京东

Map小练习

使用HashMap添加三个员工对象,要求:
键:员工id
值:员工对象

且遍历显示工资18000的员工至少使用两种遍历方式
员工类:姓名,工资,员工id

public class test4 {@SuppressWarnings({"all"})public static void main(String[] args) {HashMap map = new HashMap();staff s1 = new staff(01,"李四",16000);staff s2 = new staff(02,"王五",23000);staff s3 = new staff(03,"赵三",12000);staff s4 = new staff(04,"李明",19000);map.put(s1.id,s1);map.put(s2.id,s2);map.put(s3.id,s3);map.put(s4.id,s4);//第一种:获取直接获取所有值,判断运行类型是否是staff,如果是就向下转型,再判断薪水决定是否输出Collection c = map.values();for (Object value:c) {if (value instanceof staff){staff s = (staff) value;if (s.sal>18000){System.out.println(s);}}}//第二种:直接获取所有键和值Set entrySet = map.entrySet();for (Object entry:entrySet) {Map.Entry entry1 = (Map.Entry) entry;staff s = (staff) entry1.getValue();if (s.sal>18000){System.out.println(s);}}}
}
class staff{String name;int id;double sal;public staff(int id,String name,double sal) {this.name = name;this.id = id;this.sal = sal;}@Overridepublic String toString() {return "staff{" +"name='" + name + '\'' +", id=" + id +", sal=" + sal +'}';}
}

HashMap小结

  • Map接口的常用实现类:HashMap,Hashtable,Properties,ThreeMap
  • HashMap是Map接口使用频率最高的实现类
  • HashMap是以key-value对的方式来存储数据的
  • key不能重复,但是值可以重复,运行使用null作为存入的数据
  • 如果添加相同的key,则会覆盖原来的key-value,等同于替换
  • 与HashSet一样,HashMap不保证映射的顺序,因为底层是以hash表的方式来存储的(jdk8的hashMap底层:数组+链表+红黑树)
  • HashMap没有实现同步,因此是线程不安全的,方法没有做同步互斥的操作,没有synchronized

HashMap底层机制及源码刨析

扩容机制

  1. HashMap底层维护了Node类型的数组table,默认为null
  2. 当创建对象时,将加载因子(loadfactor)初始化为0.75.也就是当table数组存放的元素数到达整体数组大小的75%时,就会进行扩容
  3. 当添加k-y时,会先通过key的哈希值得到在table的索引,然后判断该索引是否有元素,如果没有则直接添加,如果有元素就判断该位置的元素key和准备添加的key是否相等,如果相等则直接替换value,如果不相等则判断是树结构还是链表结构,如果是链表结构就直接与下一个元素判断。
  4. 第一次添加,需要扩容table数组容量为16,扩容临界值(threshold)为12,(16*0.75)
  5. 非第一次扩容就是扩容table容量为原来的2倍,临界值也为原来的2倍,以此类推
  6. 在java8中,如果一条链表的元素超过了8个且table的大小>=64就会进行树化,如果链表元素超过8个,但是table数组的大小还未超过64,那么就会先进行数组扩容,直到数组大小到达64才会进行树化

Hashtable

在这里插入图片描述

Hashtable也是Map接口的实现类,与HashMap是同级关系

Hashtable基本介绍

  1. 存放的元素也是键和值:key-value
  2. Hashtable的k-v都不能存放null,负责会抛出异常
  3. Hashtable的使用方法基本上和HashMap一致
  4. Hashtable是线程安全的,HashMap是线程不安全的

Hashtable底层介绍

初始

  1. 底层由数组Hashtable$Entry[]初始化大小为11
  2. 初始临界值threeshold 8 = 11*0.75,所以也是到75%就扩容
  3. Hashtable除了第一次初始化大小,后面扩容机制为 *2+1.

Hashtable和HashMap的选择

实现类出现版本线程安全效率是否可以存null
HashMap1.2不安全允许
Hashtable1.0安全较低不允许

Properties

Properties基本介绍

  1. Properties类继承于Hahstable类,同样实现了Map接口,也是一种键key-值value的形式保存数据
  2. Properties的使用特点和Hashtable类似
  3. Properties还可以用于从xxx.properties文件中,加载数据到Properties类对象进行读取和修改(在IO流说明)

Properties的增删改查

public class test5 {public static void main(String[] args) {Properties properties = new Properties();//增加properties.put("no1",100);properties.put("no2",200);//删除,根据key,删除key-valueproperties.remove("no1");System.out.println(properties);//改(替换)properties.put("no2",90);System.out.println(properties);//查,根据key获取valueSystem.out.println(properties.get("no2"));}
}

相关内容

热门资讯

魁拔4发蛮吉是魁拔了吗? 魁拔4发蛮吉是魁拔了吗?发现了,你可以去看魁书2,感情线也明了了,我会骗你吗?谁知道,去问王川呀
找一本小说男主好像姓凤,女主是... 找一本小说男主好像姓凤,女主是一对双胞胎的姐姐,叫什么就忘了,男二号叫龙飞,和双胞胎妹妹相爱的女主姓...
明朝精彩故事 明朝精彩故事喜欢明朝的故事,建议看【明朝那些事儿】用现代的语言说明朝的故事,你会喜欢的,里面语言很幽...
用过‘千万别学英语’的请进 用过‘千万别学英语’的请进我觉得这书没什么意思,有时候任何东西都是只适合一部分人的。我每天听那些磁带...
学英语时英美式发音混在一起了怎... 学英语时英美式发音混在一起了怎么办?哪种发音好?学的词汇是英式发音,但是很多听力却是美式发音的,怎么...
"我不是个稻草人,不能说不能动... "我不是个稻草人,不能说不能动"是哪首歌里的?稻草人,林志颖唱的林志颖演唱的 稻草人林志颖的稻草人
恶魔猎手有什么那么厉害,高手看... 恶魔猎手有什么那么厉害,高手看中他那点厉害恶魔猎手有什么那么厉害,高手看中他那点厉害速度技能都很好。...
请问这样的短信该怎样回 请问这样的短信该怎样回夸奖夸奖,久闻阁下大名,今日一见果然名不虚传。肥硕如象,真是过犹而不及。小生我...
女上司总来撩我怎么办,我也会把... 女上司总来撩我怎么办,我也会把持不住的找借口或是直接反撩她,我猜你也不敢,可能对你有意思,没女朋友就...
为什么良渚文化可以证明中华文明... 为什么良渚文化可以证明中华文明五千年,而龙山文化等其他文化不能证明?因为良渚文化有不少文化遗产可以证...
炎亚纶的资料。 炎亚纶的资料。去网上搜 炎亚纶
男主重生重进宗门 不是都市小说... 男主重生重进宗门 不是都市小说 以前在师傅手下学药后来和师姐好上了重生小说一般都不会放过师姐。。。
万章曰:"尧以天下与... 万章曰:"尧以天下与舜,有诸?(孟子的学生)万章问(孟子):“尧把天下授与舜,有这回事吗?” 问的是...
写近义词饱胀对什么清早对什么依... 写近义词饱胀对什么清早对什么依然对什么?饱胀对饱满,清早对清晨,依然对依旧饱胀的近义词: 饱足 饱满...
梦到在上课 梦到在上课老师你也敢戏弄?别说给小鞋你穿,紧紧鞋带都够你受的。这是你潜意识里发泄心理压力,而达到心理...
怎么写一个人很温柔,写一段话 怎么写一个人很温柔,写一段话我不知道那些鸿雁究竟是怎样掠夺了我忧郁无助的天空。就像你撩动温柔浸渍了我...
中风了应该怎样处理? 中风了应该怎样处理?中风多由脑血管疾病引发,是一种常见急症。处理原则是:保持病人安静,让病人卧下,将...
盘点2021高评分的古装剧,哪... 盘点2021高评分的古装剧,哪部剧最让你感到意难平?杨幂的斛珠夫人 。在这部剧的结局当中,男一男二,...
奔字的笔顺笔画顺序 奔字的笔顺笔画顺序汉字: 奔 读音: bèn bēn 部首: 大 笔画...
智商跟性格有关吗 智商跟性格有关吗有关啊,有相关的研究,但是相关未必是因果,可能是因为智力高所以才有的那些性格或者别的...