1.为什么重写equals要重写hashCode
-
hashCode()
与哈希表:
在Java中,哈希表(如HashMap、HashSet等)是基于哈希函数的数据结构。哈希表用来存储键值对,并允许通过键来快速查找值。在哈希表中,键的哈希码被用于计算存储位置,因此不同的键应该产生不同的哈希码以充分分散数据,减少哈希冲突。如果两个对象在equals()
方法中被认为是相等的,那么它们的hashCode()
方法应该返回相同的值,以确保它们在哈希表中能够正确存储和检索。两个对象equals = true ,那么hashCode = true;
hashCode = true,不一定equals = true;
equals = false ,hashCode可能true也可能false;
hashCode = false , equals一定等于false。 -
哈希集合与哈希映射的行为:
当你向HashSet或HashMap等使用哈希表的集合类中添加元素时,Java会首先计算每个元素的哈希码,并根据该哈希码将元素放置在合适的位置。接着,它会调用元素的equals()
方法来检查是否存在相同的元素。如果两个对象在equals()
方法中被认为是相等的,但它们的哈希码不同,会导致集合中存在两个相等的元素,这会破坏集合的一致性。简单来说就是先判断hashCode是否相同,再判断equals,这样的步骤极大优化了纯靠equals判等的速度,因为hashCode在一个对象创建之初就已经计算完成了,所以说hashCode判等的速度是块于equals的判等速度的
-
规范要求:
Java的Object
类中有这样的规定:如果两个对象通过equals()
方法比较返回true,则它们的哈希码(由hashCode()
方法返回)必须相等。因此,当你重写equals()
方法时,为了遵循这个规范,你也应该相应地重写hashCode()
方法。
综上所述,重写hashCode()
方法是为了保证在集合类中正确地处理对象的插入、查找和删除操作。如果不同时重写hashCode()
方法,会导致对象在集合中的行为不稳定,可能导致意外的结果。
String StringBuffer StringBuilder的区别
StringBuilder的拼接速度远远大于String的速度
StringBuffer跟builder逻辑一样,但是加锁了,所以速度稍微慢一些但是更加安全
-
速度远快于String的原因:
内存:由一个个电容组成一个个基本单位
内存在出场时设定:一个字节为一个存储单元
cpu把想看的地方的地址指令发给内存,内存把数据传给从cpu
理论上讲,想读一百个字节数据,cpu至少要下达一百次指令,单次通信,cpu到内存之间需要走20到30纳秒-电流在导线中的速度16万千米/s–20万千米/s
操作系统在分配内存的时候会尽可能挨在一起
所以每4096B会合成一个内存页
cpu每次只需要下达每个页的第一个物理单元的指令,只记住第一个bit点的地址,直接返回4096个物理单元的数据
所以一万字节只需要三个页来存储
页单元属于物理上重新划分的逻辑单元
如果一个页里面存两个,第一个大小不确定,不能确定第二个变量的位置,所以也是一种以空间换取时间的操作
内存为了加快速度,都是以页来分配,所以一个变量都会分配到4kB- 但是有例外,利用数组可以把多个变量存到一个页里面
在页里面的变量是不支持页拓展的,如想要字符串增加内容只能新建一个页,这是正常String逻辑
StringBuilder逻辑:跟buffer一样,只不过没锁
StringBuffer的逻辑:申请一个足够大的空间,直接在空间内增加,不用申请新的页
Buffer:缓冲的意思,带有buffer代表有足够缓冲空间的数组,不用反复申请空间,对内存的消耗大大降低
== 和 equals的区别
==:如果是基本数据类型,比较值,引用类型比较地址
equals:具体看各个类重写equals方法后的比较逻辑,比如String重写了equals后,他比较的是字符串每个位置的字符是否相同
这里要注意128陷阱
在Java中,对于基本数据类型byte
, short
, int
,以及对应的封装类Byte
, Short
, Integer
,在范围-128
到127
内的数值,Java会在启动时自动缓存这些数值的对象。这样做是为了节省内存开销和提高性能。
因此,当使用==
操作符比较两个在范围-128
到127
内的Integer
对象时,会出现预期外的结果。尽管这两个对象的值相等,但它们实际上不是同一个对象,因为缓存的原因。
Integer a = 1000;
Integer b = 1000;
System.out.println(a == b); // 输出: false
System.out.println(a.equals(b)); // 输出: true
Integer x = 100;
Integer y = 100;
Integer z = new Integer(100);
System.out.println(x == y); // 输出: true
System.out.println(x == z) //输出: false
System.out.println(x.equals(y)); // 输出: true
为了避免出现这个陷阱,通常推荐使用equals()
方法来比较Integer
对象的值,而不是使用==
操作符。这样可以确保始终对值进行比较,而不受缓存机制的影响。
ArrayList 和 LinkedList的区别
首先ArrayList底层是数组实现的,而LinkedList是基于链表实现的
由于底层的差别,所以ArrayList更适合于查找,而LinkedList更适合增删改操作
虽然他俩都实现了LIst接口,但是LinkedList还实现了Deque接口,所以可以当作队列来用