初识HashMap
1.初识HashMap
下面是出自于jdk1.8中文文档缩写的一段话
-
基于哈希表的
Map
接口的实现。这种实现提供了所有可选的Map操作,并允许null
值和null
关键。(这HashMap
类大致相当于Hashtable
,除了它是不同步的,允许空值。)这类做任何保证Map的秩序;特别是,它并不能保证订单将随时间保持恒定。这个实现的基本操作提供了稳定的性能(
get
和put
),假设哈希函数的分散元素之间的正确的桶。在集合视图迭代需要时间成正比的“能力”的HashMap
实例(桶的数量)加上其尺寸(键值对映射的数量)。因此,它是非常重要的,不设置的初始容量太高(或负载因子太低),如果迭代性能是重要的。对
HashMap
实例有影响其性能的两个参数:初始容量和负载因子。是的容量哈希表中的存储桶的数目,和初始容量仅仅是当时的哈希表的创建能力。的负载因子是如何全面衡量哈希表是可以在其容量自动增加。当哈希表中的条目数超过负荷的因素和当前容量的乘积,哈希表是重复(即内部数据结构重建),哈希表有大约两倍的存储桶的数目。作为一个一般规则,默认负载因子(。75)提供了一个很好的时间和空间成本之间的权衡。较高的值会降低空间开销,但提高查找成本(体现在大多数的
HashMap
类的操作,包括get
和put
)。预计参赛人数在Map及其负载系数应考虑设置其初始容量时,以尽量减少重复操作的次数。如果初始容量大于最大条目数除以负载因子,没有rehash操作将不会发生。如果许多映射将被存储在一个
HashMap
实例,创建了一个足够大的容量将允许映射可以存储比让它执行自动改写为增长所需要的表格更有效。注意使用多键同hashCode()
是一个肯定的方式来减缓任何哈希表的性能。改善的影响,Comparable
键时,这类可以帮助打破关系键比较的顺序使用。**请注意,此实现不同步。**如果多个线程访问一个哈希映射的同时,并至少有一个线程修改Map的结构,它必须同步外部。(结构上的修改是任何操作,添加或删除一个或多个映射;仅仅改变一个关键实例已经包含了不是一个结构上的修改。相关的价值)这通常是由一些对象同步自然封装图完成。如果该对象不存在,Map应该是“包裹”使用
Collections.synchronizedMap
方法。最好的做法是在创建时,防止意外的非同步访问的Map:MapM =集合。synchronizedmap(新HashMap(…));
所有这一类的“集合视图的方法”快速失败返回的迭代器:如果Map的结构修改,迭代器创建后的任何时间,以任何方式除了通过迭代器的
remove
方法,迭代器将抛出一个ConcurrentModificationException
。因此,在并发修改的面前,迭代器失败迅速和干净,而不是冒着任意的,非确定性的行为在未来的一个不确定的时间。注意迭代器不能快速失败行为得到保证的话,一般来说,不可能在不同步的并发修改的存在作出难以保证。快速失败迭代器扔
ConcurrentModificationException
尽最大努力的基础上。因此,要写一个程序,依靠这一例外的正确性错误:快速失败迭代器的行为只能用来检测错误。
2.简单的分析
下面先上下代码,再给大家讲解一下
Map<Student,String> map = new HashMap<Student,String>();
Student s1= new Student("孙悟空", (long) 100);
Student s2= new Student("猪八戒", (long) 101);
Student s3= new Student("沙和尚", (long) 102);
map.put(s1,"北京");
map.put(s2,"南京");
map.put(s3,"汕头");
//注意:这里是否重写了hashCode和equal方法!!!(关键)
//1.如果没有重写,比较的是地址,所以能成功插入
//2.如果重写了两个方法,则插入失败,因为这是一个不允许重复的集合
map.put(new Student("沙和尚",(long)102),"南京");
System.out.println("元素的个数是:"+map.size());
System.out.println(map.toString());
hashCode和equals是保证hashmap元素的key不重复的一个原因
如果想要让key不重复,需要重写equal和hashcode的方法,这样就能保证key不重复
如果没有重写这两个方法,hashmap的key比较的是两个地址,所以会导致key没有重复,New出来的对象,所分配的地址是不同的
如果使用lombok插件的话,默认全部重写了equal和hashcode
遍历:
//遍历hashMap集合(KeySet方法)
for (Student key:map.keySet()) {
//map.get(key)是值
System.out.println(key.toString()+"主键对应的值========================="+map.get(key));
}
System.out.println("=====================");
//遍历hashMap集合(entrySet)
for (Map.Entry<Student,String> entry: map.entrySet()) {
System.out.println(entry.getKey()+"==========="+entry.getValue());
}
遍历其实没有什么特别要讲的,主要敲几遍就记得了,用foreach去遍历
判断
//判断
System.out.println(map.containsKey(new Student("沙和尚",(long)102)));
System.out.println(map.containsValue("南京"));
判断也需要注意是否重写了hashCode和Equal方法
总结: 江南小码哥对于hashMap初识的讲解就到这里,总的来说,需要格外注意的点是,hashmap的存储机制还有对于hashcode和equal方法的联系!
方便大家练习,我贴个全代码
/**
* @version: 1.0
* @author: WSY
* @className: Test
* @packageName:
* @description:
* @date: 2021-03-19 17:14
*/
public class Test {
public static void main(String[] args) {
Map<Student,String> map = new HashMap<Student,String>();
Student s1= new Student("孙悟空", (long) 100);
Student s2= new Student("猪八戒", (long) 101);
Student s3= new Student("沙和尚", (long) 102);
map.put(s1,"北京");
map.put(s2,"南京");
map.put(s3,"汕头");
map.put(new Student("沙和尚",(long)102),"南京");
System.out.println("元素的个数是:"+map.size());
System.out.println(map.toString());
//遍历hashMap集合(KeySet方法)
for (Student key:map.keySet()) {
//map.get(key)是值
System.out.println(key.toString()+"主键对应的值========================="+map.get(key));
}
System.out.println("=====================");
//遍历hashMap集合(entrySet)
for (Map.Entry<Student,String> entry: map.entrySet()) {
System.out.println(entry.getKey()+"==========="+entry.getValue());
}
//判断
System.out.println(map.containsKey(new Student("沙和尚",(long)102)));
System.out.println(map.containsValue("南京"));
}
}
上一篇: dev_name
下一篇: HashMap 初始化(1.7)