Java面试题系列——JavaSE面试题(集合二)

1、是否写过Hash底层,了解过什么?

常用HASH函数:
直接取余法: f(x)-=x mod max;maxM一般是不太接近 24的一个质数。
乘法取整法:f(x)=trunc((x/maxX)*maxlongit)mod maxM, 主要用于实数。
平方取中法:f(x)=(x*x div 1000) mod 1000000);平方后取中间的,每位包含信息比较多。

Hash在Java中的使用:

(1)hashcode:hashcode就是通过hash函数得来的,hashcode就是在hash表中有对应的位置,对象的物理地址就是hashcode.。hashcode的作用:比如有一个可以存放1000个数的内存,在其中存放1000个数,存一个数字就要遍历一遍,看看有没有相同的数,数字越来越多的时候比较越来越多。如果用hash去存这个1000个数字的话,取一个15为关键字hash表中有16个位置,这时候去存的时候就相当于把1000个数分成15分去存储,当去查找的话,先去查找数字的hashcode,当他们的hashcode相等的时候,在去对比他们的equals方法。效率就会高很多。

(2)equals方法和hashcode的关系:hashcode相等和两个对象是否相等构成了必要不充分的关系,两个对象相等hashcode一定相等,但是hashcode相等两个对象不一定相等。

(3)为什么要重写equlas:

默认equals在比较两个对象时,是看他们是否指向同一个地址的。有时,我们希望两个对象只要是某些属性相同就认为他们的quals为true。比如:

Student s1 = new Student(1,"name1");

Student s2 = new Student(1,"name1");

如果不重写equals的话,他们是不相同的,所以我们要重些equals,判断只要他们的id和名字相同equals就为true,在一些集合里有时也这样用,集合里的contain也是用equals来比较。
 

2、Collection 集合和Map体系集合的区别?

(1)区别:Collection : 单列集合。Map : 双列集合,键和值一一映射,针对键有效,跟值无关。

(2)联系:HashSet 集合的add()方法依赖于Map接口的子实现类HashMap集合的put()方法
TreeSet 集合的add()方法依赖于Map接口的子实现类TreeMap 集合的put()方法。

3、HashMap 在JDK1.7 和JDK1.8的区别?

HashMap在1.7和1.8中最大的区别就是底层数据结构的变化,在1.7中HashMap采用的底层数据结构是数组+链表的形式,而在1.8中HashMap采用的是数组+链表+红黑树的数据结构。

4、HashSet的去重原理?

        (1)泛型是基本数据类型:int、float、long与double类型:int类型自身的值作为hashcode进行值的比较。float、long与double类型通过类型转成int类型并进行比较。boolean类型:对于Boolean类型其实是最简单的,因为Boolean类型就只有true和false两种,那么我们只需要认为规定两个数字作为其HashCode就可以。JAVA官网给出的数字是:1231和1237。String类型:对于String类型而言,其实是可以类比进制计算的方式来规定,那么对于“abcd”而言,我们知道‘a’本身即是可以用ascall码,我们可以类比类比进制的运行:“abcd” = (a * n^3) +(b *n^2) + (c * n^1) +(d * n^0)。

        (2)自定义对象:1.不重写hashCode方法和Equal方法:hash值不相同,那么肯定可以添加成功。2.重写了系统的hashCode方法和equals方法:java会根据重写的方法进行比较去重。3.个性化定制,自己重写hashCode方法和equals方法:只需要满足自身写的方法即可。

5、如何获得Map集合中的所有的Key?

(1)获取map中的全部键值(keySet方法),输出采用lambda表达式:

Map<String, Object> attrMap = Files.readAttributes(path, "*", LinkOption.NOFOLLOW_LINKS);
        //获取map中的全部键值
Set<String> keySet = attrMap.keySet();
keySet.forEach(key -> System.out.println(key));

(2)获取map中的全部 value值,(values 方法),输出采用foreach:

Collection<Object> values = attrMap.values();
for (Object value: values) {
     System.out.println("map中的value值为:" + value);
}

(3)同时获取 key值 和 value值 (entrySet 方法)。输出采用了两种方法,iterator迭代器 或者 foreach循环,lambda 表达式形式:

6、Collection 和 Collections 的区别是啥?

1、Collection是最基本的集合接口,Collection派生了两个子接口list和set,分别定义了两种不同的存储方式。2、Collections是一个包装类,它包含各种有关集合操作的静态方法(对集合的搜索、排序、线程安全化等)。

7、HashMap 什么情况下会产生死锁的问题?如何解决

HashMap是非线程安全,死锁一般都是产生于并发情况下。我们假设有二个进程T1、T2,HashMap容量为2,T1线程放入key A、B、C、D、E。在T1线程中A、B、C Hash值相同,于是形成一个链接,假设为A->C->B,而D、E Hash值不同,于是容量不足,需要新建一个更大尺寸的hash表,然后把数据从老的Hash表中 迁移到新的Hash表中(refresh)。这时T2进程闯进来了,T1暂时挂起,T2进程也准备放入新的key,这时也 发现容量不足,也refresh一把。refresh之后原来的链表结构假设为C->A,之后T1进程继续执行,链接结构 为A->C,这时就形成A.next=B,B.next=A的环形链表。一旦取值进入这个环形链表就会陷入死循环。

解决方法:使用ConcurrentHashMap进行替代,ConcurrentHashMap是一个线程安全的Hash Table。 可能有人会使用HashTable。当然HashTable也是线程安全,但HashTable锁定的是整个Hash表,效率相对比较低。而ConcurrentHashMap可以做到读取数据不加锁,并且其内部的结构可以让其在进行写操作的时候能够将锁的粒度保持地尽量地小。

持续更新中,敬请期待!

参考文章:

hash底层_Guideuhome635的博客-CSDN博客

hash详解(深入底层)_公子半岛的博客-CSDN博客_hash详解

Java Collection集合和Map集合区别与汇总_Acybee的博客-CSDN博客_collection和map的区别

HashSet去重复原理解析_Code攻城狮的博客-CSDN博客_hashset去重原理

每天睡前30分钟阅读Day5_Map中全部Key值,全部Value值获取方式_Janson666的博客-CSDN博客_map如何获取所有的key

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小海海不怕困难

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值