网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
- 当类没有覆盖
equals()
方法时,则通过equals()
比较的是该类的两个对象,这种情况等价于==。 - 当类有覆盖
equals()
方法时,一般我们会通过比较两个对象的内容来判断是否相等。
public class Car {
public static void main(String[] args) {
String a="一键三连";//常量池中
String b="一键三连";
String c=new String("一键三连");//引用
String d=new String("一键三连");
System.out.println(a==b);//true,指向常量池同一个地址
System.out.println(c==d);//false,两个不同的引用地址
System.out.println(a.equals(b));//true,判断内容
System.out.println(c.equals(d));//true
}
}
注意:
String
中的equals()
方法是被重写过的,因为object
中的equals()
方法比较的是对象的内存地址,而String
中的equals()
方法是比较对象的值。- 当创建
String
类型的对象时,虚拟机会再常量池中查找是否有已存在的值相同对象,若有则把它赋给当前引用,没有的话则重新创建一个。
hashcode()和equals()
你知道为什么重写equals()
方法必须重写hashcode()
方法吗?
先介绍下hashcode
:hashcode()
的作用是获取一个int整数即哈希码,也称为散列码。哈希码是确定对象在哈希表中的索引位置,Java中的所有类都包含该函数。
哈希码在HashSet
中应用:当把对象加入HashSet
时,HashSet
会先计算对象的hashcode
来判断对象加入的位置,同时也会与该位置其他加入对象的hashcode
作比较,若没有相符的hashcode
则会假设对象没有重复出现,否则会调用equals()
方法来检查哈希码相同的对象内容是否相同,若内容也相同,HashSet
就不会让其成功加入;否则的话就会重写散列到其他位置。通过hashcode
大大减少了equals
的调用次数,提高执行效率。这也回答了开头的问题。
hashcode()
和equals()
相关规定:
- 若两个对象相等,则
hashcode
一定是相同的,调用equals()
也都是返回true - 两个对象有相同的
hashcode
,但它们不一定相等 - 因此
equals()
覆盖的地方,hashcode()
方法也必须覆盖。 hashcode()
默认是对堆上的对象产生独特值,如果没有重写hashcode()
,则该class的两个对象无论如何都不会相等。
transient关键字
对于不想进行序列化的变量,使用transient
关键字修饰。当对象被反序列化时,被transient
关键字修饰的变量值不会被持久化和恢复。transient
只能修饰变量,不能修饰方法和类。
BIO、NIO和AIO
- BIO(Blocking I/O,同步阻塞I/O模式),数据的读取写入必须阻塞在一个线程内等待其完成。让每个连接专注于自己的I/O并且编程模式简单,不用过多考虑系统加载、限流等问题,但是连接数非常大时就无能为力了。
- NIO(Non-blocking/New I/O,同步非阻塞I/O模式),支持面向缓冲的,基于通道的I/O操作方法。阻塞模式使用就像传统中的支持一样,较为简单,但是性能和可靠性不好,而非阻塞模式正好与之相反,对于高负载、高并发的应用程序,应使用NIO模式开发。
- AIO(Asynchronous I/O,异步非阻塞模式),异步I/O是基于回调机制实现的,也就是应用操作之后会直接返回,而不是阻塞在那里,当后台处理完成后,操作系统会通知相应的线程进行后续的操作。
Java集合
ArrayList和LinkedList
- 线程安全
ArrayList
和LinkedList
都是不同步的,也就是线程不安全,vector
是同步的,线程安全。 - 底层数据结构
ArrayList
底层使用的是Object
数组,LinkedList
底层使用的是双向链表。 - 插入和删除元素
ArrayList
采用数组存储,所以插入和删除受元素位置影响;LinkedList
采用链表存储,所以插入和删除元素时受到元素位置影响。 - 快速随机访问
快速随机访问是通过元素的序号快速获取元素对象,通过底层数据就够就知道了,ArrayList
支持,LinkedList
不支持。 - 内存空间占用
ArrayList
的空间主要浪费在了list列表的结尾会预留一定的容量空间,而LinkedList
主要花费在每一个元素都要比ArrayList
更多的空间,因为存前驱后继节点及数据等。
HashMap和HashTable
- 线程安全
HashMap
是线程不安全的,而HashTable
是线程安全的,因为HashTable
的内部实现都加了synchronized
修饰。 - 效率
因为上述线程安全的问题,HashMap
效率也就更高一点。 - Null
HashMap
中可以把null
作为键或值,而HashTable
不支持。 - 扩容
若创建时未指定容量,HashMap
初始为
16
16
16,每次扩容为2倍,HashTable
初始为
11
11
11,并且每次扩容为
2
n
1
2n+1
2n+1。
若创建时指定了容量,HashMap
会将其扩充至
2
2
2的幂次方大小,HashTable
会直接使用给定的容量。
5. 底层数据结构
HashMap
jdk1.8以后,当链表长度超过阈值(默认8)时,会转换为红黑树,以减少搜索时间,而HashTable
没有这样的机制。
(
插播反爬信息)博主CSDN地址:https://wzlodq.blog.csdn.net/
HashMap
的长度为什么是2的幂次方?
为了能让HashMap
减少碰撞高效存储,要尽量把数据分配均匀。首先哈希值的取值范围很大,有将近40亿的空间,内存时放不下的,换言之,哈希值并不能直接使用,需要对数组的长度进行取模,得到的余数就是对应的数组下标。
而设计成2的幂次就是因为如果取余操作中除数是2的幂次的话,就等价于与其除数减一的与操作,也就是说
h
a
s
h
%
l
e
n
g
t
h
=
(
l
e
n
g
t
h
−
1
)
&
h
a
s
h
hash%length=(length-1)&hash
hash%length=(length−1)&hash,而采用二进制位运算可以大大提高效率,这也就是为什么HashMap
的长度是2的幂次方。
HashMap底层实现
JDK1.8之前:
JDK1.8之前HashMap
底层是数组和链表结合在一起使用也就是链表散列,HashMap
通过key的hashcode经过扰动函数处理后得到hash值,然后通过
(
n
−
1
)
&
h
a
s
h
(n-1)&hash
(n−1)&hash判断当前元素存放的位置,如果当前位置存在元素的话,就判断该元素与要存入的元素的hash值以及是否相同,若相同则直接覆盖,否则通过拉链法来解决冲突。所谓扰动函数指的就是HashMap
的hash方法。使用hash方法之后可以减少碰撞。
JDK1.8之后:
优化了哈希冲突的解决方法,当链表长度大于阈值(默认为8)时,会将链表转换为红黑树,以减少搜索时间。
comparable和comparator
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
olor_FFFFFF,t_70#pic_center)
comparable和comparator
[外链图片转存中…(img-Sx9dcWad-1715659167629)]
[外链图片转存中…(img-u576AsUC-1715659167629)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新