1.为什么重写 equals 还要重写 hashcode?
1,理解为什么要重写?
equals是比较两个对象是否相等,他和hashcode都是Object中的方法,我们先做一个假设,不去重写equals和hashcode方法,看下面这行代码:
Person a=new Proson("张三",18);
Person b=new Proson("张三",18);
如果我们不重写equals方法,那么就会调用Object类中的默认方法,比较a和b的内存地址,但是由于没有重写方法,就会将相同内容的不同引用存放在不同的hashcode之中。不去重写hashcode,hashcode是本地方法,Java的内存是安全的,无法根据散列码来查看到两个对象的地址,但是hashcode就是由对象的内存地址运用哈希算法生成的。
那么我们去重写equals,不重写hashcode方法,那么hashcode就是Object的默认方法,显而易见的是a!=b,从而推理就是a和b的hashcode值不相等。
但是重写了equals方法,a.equals(b)的结果一定为true,这个结果就和上面相反,因为hashcode的原则,如果equals相等,那么hashcode也一定相等,所以hashcode一定要重写。
有四条规律,或者是说原则:
- 两个对象相等,hashcode一定相等
- 两个对象不等,hashcode不一定不等
- hashcode相等,两个对象不一定相等
- hashcode不等,两个对象一定不等
其次,对于重写hashcode方法来说也是一个提高效率的方法,首先先比较hashcode是否相等,如果不等也就不用比较equals的值。
重写equals的方法是针对于在HashSet集合中的自定义的类对象,由于set集合是无序的,所以避免重复,我们才要重写。
2.== 和 equals 比较的区别
“==”是比较基本数据类型;如果是引用数据类型,则比较所指向对象的地址值。
equals比较的是所指向的对象的地址值,一般情况下,重写之后比较的是对象的值。
其中,如果equals没有重写,那么就是相当于“==”,这样比较的是引用类型所指的对象的地址值。
String类中的equals是被重写的,会直接比较对象的值。
3.为啥有时会出现 4.0 - 3.6 = 0.40000001 这种现象?
因为浮点数进行加减的时候是将其转换成二进制的形式来计算的,但是二进制的精度无法表示1/10,就像十进制无法表示1/3。
4.介绍 Java 的集合类
主要分为:set list map
Java容器分为Collection 和 Map 两大类,其中Collection集合的子接口有Set、List、Queue三种子接口,Map也是一个接口,但是不是Collection的子接口。
List:一个有序容器,元素可以重复,可以插入多个null元素,元素都有索引。常用的实现类有 ArrayList、LinkedList 和 Vector。
Set:一个无序容器,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。Set 接口常用实现类是 HashSet、LinkedHashSet 以及 TreeSet。
Map:是一个键值对集合,存储键、值和之间的映射。 Key无序,唯一;value 不要求有序,允许重复。从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。Map 的常用实现类:HashMap、TreeMap、HashTable、LinkedHashMap、ConcurrentHashMap。
4.1说一下 HashMap 的实现原理?
HashMap是基于Map接口实现的,允许由null键和null值的存在,存储的数据都是无序的。
HashMap的数据结构是一个数组和链表的结合体,“链表散列”结构。
它的核心是基于Hash算法是实现的:
- 存储时,如果出现相同hashcode的key时,有两种处理方法,如果key相同,就覆盖,如果key不同,就将key-value存入HashMap之中。
- 当我们想要put元素的时候,首先得到的是key的hashcode值,然后根据,Hash的算法计算出数组的下标。
- 获取时,找到对应的数组下标,然后判断key的值是否相同,然后直接返回,就是value。
4.2解决Hash冲突
HashMap解决hash冲突的原理是,使用了数组的存储机制,将冲突的key放入到链表中,冲突就在链表中进行对比。
数组和链表是Java中保存数据比较简单的数据结构,其中数组和链表各有各的优点和缺点,数组方便查找,但是删除和插入困难,耗时较多,链表却恰恰相反,查找需要从头开始,比较麻烦,但是删除和插入却十分方便。于是我们结合两者之间的优点,使用一种叫做拉链法的方式可以解决哈希冲突。(JDk1.7)
拉链法就是将数组和链表组合起来,其中每一个数组就是一个链表,如果遇到hash冲突,就可以将hash冲突的值放入链表之中。
在JDK1.8之后,虽然也还是将数组和链表组合在一起,但是当链表的长度大于一个阈值(8)的时候,就会将链表转换为红黑树,用来减少搜索的时间,由于红黑树是一个自平衡的二叉树,所以时间复杂度为O(logn)