随便学学
作者:互联网
TCP的三次握手和四次挥手
TCP协议是7层网络协议中的传输层协议,负责数据的可靠传输。
在建立TCP连接时,需要通过三次握手来建立,过程是:
-
客户端向服务端发送SYN
-
服务端接收到SYN后,向客户端发送一个SYN_ACK
-
客户端收到SYN_ACK后,再给服务端发送一个ACK
在TCP连接时,需要通过四次挥手来断开,过程是:
- 客户端向服务端发送FIN
- 服务端接收到FIN后,向客户端发送ACK,表示我接收到了断开连接的请求,客户端你可以不发数据了,不过服务端这边可能还有数据正在处理
- 服务端处理完数据后向客户端发送FIN,表示客户端你可以断开连接了
- 客户端收到FIN后,向服务端发送ACK,表示我断开连接了
String、StringBuffer和StringBuilder的区别
- String是不可变的,如果尝试去修改,会生成一个新的字符串对象,StringBuffer和StringBuilder是可变的
- StringBuffer是先线程安全的,StringBuilder是线程不安全的,所以在单线程环境下使用StringBuilder效率会更高
ArrayList和LinkedList有哪些区别
- 首先,他们的底层数据结构不同,ArrayList底层是基于数组实现的,LinkedList底层是基于链表实现的
- 由于底层数据结构不同,他们所使用的场景也不同,ArrayList更适合随机查找,LinkedList更适合删除和添加
- 另外ArrayList和LinkedList都实现了List接口,但是LinkedList还额外实现了Deque接口,所以LinkedList还可以当作队列来使用
CopyOnWriteArrayList的底层原理是怎样的
- 首先CopyOnWriteArrayList内部也是用数组来实现的,在向CopyOnWriteArrayList添加元素时,会复制一个新的数组,写操作在新数组上进行,读操作在原数组上进行
- 写操作加锁,防止出现并发导致数据丢失的问题
- 写操作结束之后会把原数组指向新数组
- CopyOnWriteArrayList允许在写操作时来读取数据,大大提高了读的性能,因此适合读多写少的应用场景,但是CopyOnWriteArrayList会比较占内存,同时读到的数据可能不是最新的数据,所以不适合实时性要求很高的场景
HashMap的扩容机制原理
1.7版本
- 先生成新数组
- 遍历老数组中的每个位置上的链表上的每个元素
- 取每个元素的key,并基于新数组长度,计算出每个元素在新数组中的下标
- 将元素添加到新的数组中去
- 所有元素转移完了之后,将新数组赋值给HashMap对象的table属性
1.8版本
-
先生成新数组
-
遍历老数组中的每个位置上的链表或红黑树
-
如果是链表,则直接将链表中的每个元素重新计算下标,并添加到新数组中去
-
如果是红黑树,则先遍历红黑树,计算出红黑树中每个元素对应在新数组中的下标位置
a.统计每个下标位置的元素个数
b. 如果该位置下的元素个数超过了8,则生成一个新的红黑树,并将根节点添加到新数组的对应位置
c. 如果该位置下的元素个数没有超过8, 那么则生成一个新的链表,并将链表的头节点添加到新数组的对应位置
-
所有元素转移完了之后,将新数组赋值给HashMap对象的table属性
ConcurrentHashMap的扩容机制
1.7版本
- 1.7版本的ConcurrentHashMap是基于Segment分段实现的
- 每个Segment相当于一个小型的HashMap
- 每个Segment内部会进行扩容,和HashMap的扩容逻辑类似
- 先生成新的数组,然后转移元素到新数组中
- 扩容的判断也是每个Segment内部单独判断的,判断是否超过阈值
1.8版本
- 1.8版本的ConcurrentHashMap不再基于Segment实现
- 当某个线程进行put时,如果发现ConcurrentHashMap正在进行扩容那么该线程一起进行扩容
- 如果某个线程put时,发现没有正在进行扩容,则将key-value添加到ConcurrentHashMap中,然后判断是否超过阈值,超过了则进行扩容
- ConcurrentHashMap是支持多个线程同时进行扩容的
- 扩容之前也先生成一个新的数组
- 在转移元素时,先将原数组分组,将每组分给不同的线程来进行元素的转移,每个线程负责一组或多组的元素转移工作
java包装类型与基本类型的区别
-
包装类型可以为null,而基本类型不可以
-
包装类型可用于泛型,而基本类型不可以
-
基本类型比包装类型更高效,频繁的拆箱装箱会导致内存碎片过多,引发频繁的垃圾回收,影响性能。
-
两个包装类型的值可以相同,但不相等
什么场景使用最优
- 缓存范围内使用速度最快。
- 对数据库的操作,需要对数值类型进行判空。
序列化和反序列化
概念
- 序列化:把java对象转换为字节序列的过程
- 反序列化:把字节序列转换为java对象的过程
用途
- 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;(持久化对象)
- 在网络上传送对象的字节序列。(网络传输对象)
使用
如果一个对象想要实现序列化必须实现下面两个接口之一:
- Serializable 接口
- Externalizable 接口
New与反射创建对象的区别
- new出来的对象无法访问其中的私有属性,但是通过反射出来的对象我们可以通过setAccessible()方法来访问其中的私有属性
- 使用new创建一个对象实例的时候必须知道全类名,但是通过反射创建对象有时候不需要知道类名也可以,jdk动态代理
HashCode
HashCode的作用是获取哈希码,也称散列码,它实际上是返回一个int整数,这个哈希码的作用是确定该对象在哈希表中的索引位置
- 如果两个对象相等,则hashcode一定也相等
- 两个对象相等,对两个对象调用equals方法返回true
- 两个对象有相同的hashcode值,他们不一定相等
- hashcode的默认行为是对堆上的对象产生独特的值,如果没有重写hashcode,则该class的两个对象无论如何都不会相等
如何实现一个IOC容器
- 配置文件配置包扫描路径
- 递归包扫描获取.class文件
- 反射,确定需要交给IOC管理的类
- 对需要注入的类进行依赖注入
Java类加载器
JDK自带有三个类加载器:BootStrap Classloader、ExtClassLoader、AppClassLoader。
BootStrapClassLoader是ExtClassLoader的父类加载器,默认负责加载%JAVA_HOME%lib下的jar包和class文件
ExtClasssLoader是AppClassLoader的父类加载器,负责加载%JAVA_HOME%/lib/ext文件夹下的jar包和class类
AppClassLoader是自定义类加载器的父类,负责加载classpath下的类文件
继承ClassLoader实现自定义类加载器
双亲委托模型
好处:
- 安全行,避免了用户自己编写的类动态替换Java的一些核心类,比如String
- 避免了类的重复加载,因为JVM中区分不同类,不仅仅是根据类名,相同的class文件被不同的ClassLoader加载就是不同的两个类
GC如何判断对象可以被回收
- 引用计数法:每个对象有一个引用计数属性,新增一个引用时计数+1,引用释放时计数-1,计数为0时可以被回收
- 可达性分析法:从GC Roots开始向下搜索,搜索走过的路径称为引用链。当一个对象到GC Roots没有任何引用链时,则证明此对象不可用,那么虚拟机就判断是可回收对象
引用计数法:可能会出现A引用了B,B又引用了A,这时候就算他们都不再使用了,但因为相互引用计数器=1永远无法被回收
GC Roots的对象有:
- 虚拟机栈中引用的对象
- 方法区中静态类属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中JNI(即一般说的Native方法)引用的对象
可达性算法中的不可达对象并不是立即死亡的,对象拥有一次自我拯救的机会。对象被系统宣告死亡至少要经历两次标记过程:第一次是经过可达性分析发现没有与GC Roots相连的引用链,第二次是在由虚拟机自动建立的Finalizer队列中判断是否需要执行Finalizer方法,执行后还不可达则进行回收,否则对象复活。
标签:学学,对象,元素,随便,引用,数组,客户端,加载 来源: https://www.cnblogs.com/gc5132/p/15149189.html