Java基础面试题

巩固基础,砥砺前行 。
只有不断重复,才能做到超越自己。
能坚持把简单的事情做到极致,也是不容易的。

Java基础面试题

什么是面相对象?谈谈对面向对象的理解?
jdk jre jvm他们的关系是什么?

JDKOava SE Development Kit), Java标准开发包,它提供了编译、运行Jsa程序所需的各种工具和资源,包括Java编译器、Java运行时环境,以及常用的Java类库等·JRE(Java Runtime Environment),Java运行环境,用于运行Java的字节码文件。JRE中包括了JVM以及JVM工作所需要的类库,普通用户而只需要安装JRE来运行Java程序,而程序开发者必须安装JDK来编译、调试程序。
·JVM(Java Virtual Mechinal),Java虚拟机,是JRE的一部分,它是整个java实现跨平台的最核心的部分,负责运行字节码文件。
我们写Java代码,用txt就可以写,但是写出来的Java代码,想要运行,需要先编译成字节码,那就需要编译器,而JDK中就包含了编译器javac,编译之后的字节码,想要运
行,就需要一个可以执行字节码的程序,这个程序就是JVM(Java虚拟机),专门用来执行Java字节码的。
如果我们要开发Java程序,那就需要JDK,因为要编译Java源文件。
如果我们只想运行已经编译好的Java字节码文件,也就是*.class文件,那么就只需要JRE.
JDK中包含了JRE,JRE中包含了JVM。
另外,JVM在执行Java字节码时,需要把字节码解释为机器指令,而不同操作系统的机器指令是有可能不一样的,所以就导致不同操作系统上的JM是不一样的,所以我们
十女装儿水K的架要选择操作系统
另外,JVM是用来执行Java字节码的,所以凡是某个代码编译之后是Java字节码,那就都能在JM上运行,比如Apache Groovy,Scala and Kotlin等等。

==和equal ?

==比较的是栈中的值。基本类型比较的是数值(在栈中初始化),对象比较的是堆中对象的地址.

·==:如果是基本数据类型,比较是值,如果是引用类型,比较的是引用地址
.equals:具体看各个类重写equals方法之后的比较逻辑,比如String类,虽然是引用类型,但是String类中重写了equals方法,方法内部比较的是字符串中的各个字符是
否全部相等。

hashCode()与equals()之间的关系

在Java中,每个对象都可以调用自己的hashCode0方法得到自己的哈希值(hashCode),相当于对象的指纹信息,通常来说世界上没有完全相同的两个指纹,但是在Java中做不到这么绝对,但是我们仍然可以利用hashCode来做一些提前的判断,比如:
·如果两个对象的hashCode不相同,那么这两个对象肯定不同的两个对象
。如果两个对象的hashCode相同,不代表这两个对象一定是同一个对象,也可能是两个对象
·如果两个对象相等,那么他们的hashCode就一定相同
在Java的一些集合类的实现中,在比较两个对象是否相等时,会根据上面的原则,会先调用对象的hashCode(方法得到hashCode进行比较,如果hashCode不相同,就可以直接认为这两个对象不相同,如果hashCode相同,那么就会进一步调用equals0方法进行比较。而equals0方法,就是用来最终确定两个对象是不是相等的,通常equals方法的实现会比较重,逻辑比较多,而hashCode0主要就是得到一个哈希值,实际上就一个数字,相对而言比较轻,所以在比较两个对象时,通常都会先根据hashCode想比较一下。
所以我们就需要注意,如果我们重写了equals0方法,那么就要注意hashCode0方法,一定要保证能遵守上述规则。

List和Set的区别

.List:有序,按对象插入的顺序保存对象,可重复,允许多个Nul元素对象,可以使用Iterator取出所有元素,在逐一遍历,还可以使用get(int index)获取指定下标的元

.Set:无序,不可重复,最多允许有一个Null元素对象,取元素时只能用Iterator接口取得所有元素,在逐一遍历各个元素
ArrayList和LinkedList区别
1.首先,他们的底层数据结构不同,ArrayList底层是基于数组实现的,LinkedList底层是基于链表实现的
2.由于底层数据结构不同,他们所适用的场景也不同,ArrayList更适合随机查找,LinkedList更适合删除和添加,查询、添加、删除的时间复杂度不同
3.另外ArrayList和LinkedList都实现了List接口,但是LinkedList还额外实现了Deque接口,所以LinkedList还可以当做队列来使用

ArrayList和LinkedList区别

ArrayList:基于动态数组,连续内存存储,适合下标访问(随机访问),扩容机制:因为数组长度固定,超出长度存数据时需要新建数组,然后将老数组的数据拷贝到新数组,如果不是尾部插入数据还会涉及到元素的移动(往后复制一份,插入新元素),使用尾插法并指定初始容量可以极大提升性能、甚至超过linkedList(需要创建大量的node对象)

LinkedList:基于链表,可以存储在分散的内存中,适合做数据插入及删除操作,不适合查询:需要逐一遍历遍历LinkedList必须使用iterator不能使用for循环,因为每次for循环体内通过get()取得某一元素时都需要对list重新进行遍历,性能消耗极大。另外不要试图使用indexOf等返回元素索引,并利用其进行遍历,使用indexlOf对list进行了遍历,当结果为空时会遍历整个列表。

1.首先,他们的底层数据结构不同,ArayList底层是基于数组实现的,LinkedList底层是基于链表实现的

2.由于底层数据结构不同,他们所适用的场景也不同,ArrayList更适合随机查找,LinkedList更适合删除和添加,查询、添加、删除的时间复杂度
不同

3.另外ArrayList和LinkedList都实现了List接口,但是LinkedList还额外实现了Deque接口,所以LinkedList还可以当做队列来使用

String、StringBuffer、StringBuilder的区别

1.String是不可变的,如果尝试去修改,会新生成一个字符串对象,StringBuffer和StringBuilder是可变的
2.StringBuffer是线程安全的,StringBuilder是线程不安全的,所以在单线程环境下StringBuilder效率会更高

泛型中extends和super的区别

1.<? extends T>表示包括T在内的任何T的子类
2.<?super T>表示包括T在内的任何T的父类

HashMap的扩容机制原理

1.7版本
1.先生成新数组
2.遍历老数组中的每个位置上的链表上的每个元素
3.取每个元素的key,并基于新数组长度,计算出每个元素在新数组中的下标
4.将元素添加到新数组中去
5.所有元素转移完了之后,将新数组赋值给HashMap对象的table属性

1.8版本
1.先生成新数组
2.遍历老数组中的每个位置上的链表或红黑树
3.如果是链表,则直接将链表中的每个元素重新计算下标,并添加到新数组中去
4.如果是红黑树,则先遍历红黑树,先计算出红黑树中每个元素对应在新数组中的下标位置
a.统计每个下标位置的元素个数
b.如果该位置下的元素个数超过了8,则生成一个新的红黑树,并将根节点的添加到新数组的对应位置c.如果该位置下的元素个数没有超过8,那么则生成一个链表,并将链表的头节点添加到新数组的对应位
5.所有元素转移完了之后,将新数组赋值给HashMap对象的table属性

CopyOnWriteArrayList的底层原理是怎样的?

1.首先CopyOnWriteArrayList内部也是用过数组来实现的,在向CopyOnWriteArrayList添加元素时,会复制一个新的数组,写操作在新数组上进行,读操作在原数组上进行
2.并且,写操作会加锁,防止出现并发写入丢失数据的问题
3.写操作结束之后会把原数组指向新数组
4.CopyOnWriteArrayList允许在写操作时来读取数据,大大提高了读的性能,因此适合读多写少的应用场景,但是CopyOnWriteArrayList会比较占
内存,同时可能读到的数据不是实时最新的数据,所以不适合实时性要求很高的场景。

ThreadLocal的底层原理?

1.ThreadLocal是Java中所提供的线程本地存储机制,可以利用该机制将数据缓存在某个线程内部,该线程可以在任意时刻、任意方法中获取缓存的数据
2. ThreadLocal底层是通过ThreadLocalMap来实现的,每个Thread对象(注意不是ThreadLocal对象)中都存在一个ThreadLocalMap,Map的key为ThreadLocal对象,Map的value为需要缓存的值
3.如果在线程池中使用ThreadLocal会造成内存泄漏,因为当ThreadLocal对象使用完之后,应该要把设置的key,value,也就是Entry对象进行回收,但线程池中的线程不会回收,而线程对象是通过强引用指向ThreadLocalMap,ThreadLocalMap也是通过强引用指向Entry对象,线程不被回收,Entry对象也就不会被回收,从而出现内存泄漏,解决办法是,在使用了ThreadLocal对象之后,手动调用ThreadLocal的remove方法,手动清楚Entry对象
4.ThreadLocal经典的应用场景就是连接管理(一个线程持有一个连接,该连接对象可以在不同的方法之间进行传递,线程之间不共享同一个连接)

浏览器发出一个请求到收到响应经历了哪些步骤?

1.浏览器解析用户输入的URL,生成一个HTTP格式的请求
2.先根据URL域名从本地hosts文件查找是否有映射IP,如果没有就将域名发送给电脑所配置的DNS进行域名解析,得到IP地址
3.浏览器通过操作系统将请求通过四层网络协议发送出去
4.途中可能会经过各种路由器、交换机,最终到达服务器
5.服务器搜到请求后,根据请求所指定的端口,将请求传递给绑定了该端口的应用程序,比如8080被tomcat占用了
6.tomcat接收到请求数据后,按照http协议的格式进行解析,解析得到所要访问的servlet
7.然后servlet来处理这个请求,如果是SpringMVC中的DispatchServlet,那么则会找到对应的Controller中的方法,并执行该方法得到结果
8.Tomcat得到响应结果后封装成HTTP响应的格式,并再次通过网络发送给浏览器所在的服务器
9.浏览器所在的服务器拿到结果后再传递给浏览器,浏览器则负责解析并渲染

BIO、NIO、AIO分别是什么

1.BIO:同步阻塞10,使用BIO读取数据时,线程会阻塞住,并且需要线程主动去查询是否有数据可读,并且需要处理完
一个Socket之后才能处理下一个Socket
2.NIO:同步非阻塞10,使用NIO读取数据时,线程不会阻塞,但需要线程主动的去查询是否有10事件
3.AIO:也叫做NIO2.0,异步非阻塞10,使用AIO读取数据时,线程不会阻塞,并且当有数据可读时会通知给线程,不需
要线程主动去查询

零拷贝是什么

零拷贝指的是,应用程序在需要把内核中的一块区域数据转移到另外一块内核区域去时,不需要经过先复制到用户空间,再
转移到目标内核区域去了,而直接实现转移。

HashMap和HashTable有什么区别?其底层实现是什么?

区别:
(1)HashMap方法没有synchronized修饰,线程非安全,HashTable线程安全;
(2)HashMap分许key和value为null,而HashTable不允许
2.底层实现:数组+链表实现
jdk8开始链表高度到8、数组长度超过64,链表转变为红黑树,元素以内部类Node节点存在
·计算key的hash值,二次hash然后对数组长度取模,对应到数组下标,
·如果没有产生hash冲突(下标位置没有元素),则直接创建Node存入数组,
如果产生hash冲突,先进行equal比较,相同则取代该元素,不同,则判断链表高度插入链表,链表高度达到
8,并且数组长度到64则转变为红黑树,长度低于6则将红黑树转回链表
key为null,存在下标0的位置数组扩容

谈谈的ConcurrentHashMap的扩容机制

1.7版本
1.1.7版本的ConcurrentHashMap是基于Segment分段实现的
2.每个Segment相对于一个小型的HashMap
3.每个Segment内部会进行扩容,和HashMap的扩容逻辑类似

ConcurrentHashMap原理,jdk7和jdk8版本的区别

jdk7:
数据结构:ReentrantLock+Segment+HashEntry,一个Segment中包含一个HashEntry数组,每个HashEntry又
是一个链表结构
元素查询:二次hash,第一次Hash定位到Segment,第二次Hash定位到元素所在的链表的头部
锁:Segment分段锁Segment继承了ReentrantLock,锁定操作的Segment,其他的Segment不受影响,并发度
为segment个数,可以通过构造函数指定,数组扩容不会影响其他的segment
get方法无需加锁,volatile保证
jdk8:
数据结构:synchronized+CAS+Node+红黑树,Node的val和next都用volatile修饰,保证可见性
查找,替换,赋值操作都使用CAS
锁:锁链表的head节点,不影响其他元素的读写,锁粒度更细,效率更高,扩容时,阻塞所有的读写操作、并发
扩容
读操作无锁:
Node的val和next使用volatile修饰,读写线程对该变量互相可见
数组用volatile修饰,保证扩容时被读线程感知

Java中的异常体系

Java中的所有异常都来自顶级父类Throwable。
Throwable下有两个子类Exception和Error。
Error是程序无法处理的错误,一旦出现这个错误,则程序将被迫停止运行。
Exception不会导致程序停止,又分为两个部分RunTimeException运行时异常和CheckedException检查异常。RunTimeException常常发生在程序运行过程中,会导致程序当前线程执行失败。CheckedException常常发生在程序编译过程中,会导致程序编译不通过。

MyBatis 与Hibernate 有哪些不同?

SQL和ORM的争论,永远都不会终止
开发速度的对比:
Hibernate的真正掌握要比Mybatis难些。Mybatis框架相对简单很容易上手,但也相对简陋些。
比起两者的开发速度,不仅仅要考虑到两者的特性及性能,更要根据项目需求去考虑究竟哪一个更适合项目开发,比如:一个项目中用到的复杂查询基本没有,就是简单的增删改查,这样选择hibernate效率就很快了,因为基本的sql语句已经被封装好了,根本不需要你去写sql语句,这就节省了大量的时间,但是对于一个大型项目,复杂语句较多,这样再去选择hibernate就不是一个太好的选择,选择mybatis就会加快许多,而且语句的管理也比较方便。
开发工作量的对比:
Hibernate和MyBatis都有相应的代码生成工具。可以生成简单基本的DAO层方法。针对高级查询,Mybatis需要手动编写SQL语句,以及ResultMap。而Hibernate有良好的映射机制,开发者无需关心SQL的生成与结果映射,可以更专注于业务流程
sql优化方面:
Hibernate的查询会将表中的所有字段查询出来,这一点会有性能消耗。Hibernate也可以自己写SQL来指定需要查询的字段,但这样就破坏了Hibernate开发的简洁性。而Mybatis的SQL是手动编写的,所以可以按需求指定查询的字段。

MyBatis 与Hibernate有哪些不同?

面向对象设计,和面向表结构设计
SQL和ORM的争论,永远都不会终止
开发速度的对比:
Hibernate的真正掌握要比Mybatis难些。Mybatis框架相对简单很容易上手,但也相对简陋些。
比起两者的开发速度,不仅仅要考虑到两者的特性及性能,更要根据项目需求去考虑究竟哪一个更适合项目开发,比如:一个项目中用到的复杂查询基本没有,就是简单的增删改查,这样选择hibernate效率就很快了,因为基本的sql语句已经被封装好了,根本不需要你去写sql语句,这就节省了大量的时间,但是对于一个大型项目,复杂语句较多,这样再去选择hibernate就不是一个太好的选择,选择mybatis就会加快许多,而且语句的管理也比较方便。
开发工作量的对比:
Hibernate和MyBatis都有相应的代码生成工具。可以生成简单基本的DAO层方法。针对高级查询,Mybatis需要手动编写SQL语句,以及ResultMap。而Hibernate有良好的映射机制,开发者无需关心SQL的生成与结果映射,可以更专注于业务流程
sql优化方面:
Hibernate的查询会将表中的所有字段查询出来,这一点会有性能消耗。Hibernate也可以自己写SQL来指定需要查询的字段,但这样就破坏了Hibernate开发的简洁性。而Mybatis的SQL是手动编写的,所以可以按需求指定查询的字段。Hibernate HQL语句的调优需要将SQL打印出来,而Hibernate的SQL被很多人嫌弃因为太丑了。MyBatis的SQL是自己手动写的所以调整方便。但Hibernate具有自己的日志统计。Mybatis本身不带日志统计,使用Log4j进行日志记录。
对象管理的对比:
Hibernate 是完整的对象/关系映射解决方案,它提供了对象状态管理(state management)的功能,使开发者不再需要理会底层数据库系统的细节。也就是说,相对于常见的JDBC/SQL持久层方案中需要管理SQL语句,Hibernate采用了更自然的面向对象的视角来持久化Java应用中的数据。
换句话说,使用Hibernate的开发者应该总是关注对象的状态(state),不必考虑SQL语句的执行。这部分细节已经由Hibernate掌管妥当,只有开发者在进行系统性能调优的时候才需要进行了解。而MyBatis在这一块没有文档说明,用户需要对对象自己进行详细的管理。
缓存机制对比:
相同点:都可以实现自己的缓存或使用其他第三方缓存方案,创建适配器来完全覆盖缓存行为。
不同点:Hibernate的二级缓存配置在SessionFactory生成的配置文件中进行详细配置,然后再在具体的表-对象映
射中配置是哪种缓存。
MyBatis的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且Mybatis可以在命名空间中共享相同的缓存配置和实例,通过Cache-ref来实现。
两者比较:因为Hibernate对查询对象有着良好的管理机制,用户无需关心SQL。所以在使用二级缓存时如果出现脏数据,系统会报出错误并提示。
而MyBatis在这一方面,使用二级缓存时需要特别小心。如果不能完全确定数据更新操作的波及范围,避免Cache的盲目使用。否则,脏数据的出现会给系统的正常运行带来很大的隐患。
Hibernate功能强大了数据库无关性好,O/R映射能力强,如果你对Hibernate相当精通,而且对Hibernate进行了适当的封装,那么你的项目整个持久层代码会相当简单,需要写的代码很少,开发速度很快,非常爽。
Hibernate的缺点就是学习门槛不低,要精通门槛更高,而且怎么设计0/R映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用好Hibernate方面需要你的经验和能力都很强才行。
iBATIS入门简单,即学即用,提供了数据库查询的自动对象绑定功能,而且延续了很好的SQL使用经验,对于没有那么高的对象模型要求的项目来说,相当完美。
iBATIS的缺点就是框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。

简述Mybatis的插件运行原理,如何编写一个插件。

答:Mybatis 只支持针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis 使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invokeO方法,拦截那些你指定需要拦截的方法。
编写插件: 实现 Mybatis 的 Interceptor 接口并复写 intercept0)方法,然后在给插件编写注解, 指定要拦截哪一
个接口的哪些方法即可,在配置文件中配置编写的插件。

3.mybatis的优缺点

优点:
1、基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解
除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。
2、与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接;
3、很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要]DBC支持的数据库MyBatis都
支持)。
4、能够与Spring很好的集成;
5、提供映射标签,支持对象与数据库的ORM字段差系映射; 提供对象关系映射标签,支持对象关系组件维
护。
缺点:
1、SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。
2、SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

在这里插入图片描述

Mybatis中#仆}和$的区别是什么?

1.#0是预编译处理、是占位符,$0是字符串替换、是拼接符
2.Mybatis在处理郴时,会将sql中的#0替换为?号,调用PreparedStatement来赋值
3.Mybatis 在处理 0 时,就是把 0时,就是把 0时,就是把O替换成变量的值,调用Statement 来赋值
4.使用#可以有效的防止SQL注入,提高系统安全性
–假设2 name="zhouyu"3 password=“1 or 1=1”
5 select * from user where name = #(name} and password =#{password}将转为
6 select * from user where name = ‘zhouyu’ and password =
‘1 or 1=1’

  • from user where name = ${name} and password = ${password}将转为
    from user where name = zhouyu and password = 1 or 1=1

#和$仔的区别是什么?

#0是预编译处理、是占位符,KaTeX parse error: Expected 'EOF', got '#' at position 26: …接符。 Mybatis 在处理#̲时,会将 sql 中的#仆替换…时,就是把KaTeX parse error: Expected 'EOF', got '#' at position 25: …用Statement 来赋值;#̲的变量替换是在DBMS中、变量…的变量替换是在DBMS外、变量替换后,$对应的变量不会加上单引号
使用#可以有效的防止SQL注入,提高系统安全性。

简述Mybatis的插件运行原理,如何编写一个插件。

答:Mybatis 只支持针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis 使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的 invokeO方法,拦截那些你指定需要拦截的方法。
编写插件: 实现 Mybatis 的 Interceptor 接口并复写 intercept0)方法,然后在给插件编写注解, 指定要拦截哪一
个接口的哪些方法即可,在配置文件中配置编写的插件。
@Intercepts({@signature(type = StatementHandler.class, method = “query”,args
{Statement.class, ResultHandler.class}),
@signature(type = StatementHandler.class,method = “update”, args ={statement.class}),
@signature(type = StatementHandler.class, method Statement.class })3)

深拷贝和浅拷贝

深拷贝和浅拷贝就是指对象的拷贝,一个对象中存在两种类型的属性,一种是基本数据类型,一种是实例对象的引用。
1.浅拷贝是指,只会拷贝基本数据类型的值,以及实例对象的引用地址,并不会复制一份引用地址所指向的对象,也就是浅拷贝出来的对象,内部的类属性指向的是同一个对象
2.深拷贝是指,既会拷贝基本数据类型的值,也会针对实例对象的引用地址所指向的对象进行复制,深拷贝出来的对象,内部的属性指向的不是同一个对象

什么是浅拷贝和深拷贝?

浅拷贝(shallow copy):只复制指向某个对象的指针,而不复制对象本身,新旧对象共享一块内存;
深拷贝(deep copy):复制并创建一个一摸一样的对象,不共享内存,修改新对象,旧对象保持不变;
浅拷贝
拷贝对象和原始对象的引用类型引用同一个对象。
public class ShallowCloneExample implements Cloneable
private int[l
arr;
public ShallowCloneExample()
arr= new int[10]
for (int i=0; i< arr.length;i++
arr[i] = i;
Java
public void set(int index, int value)+
arrlindex] = value;
public int get(int index)
return arr[index];
@Override
protected ShallowCloneExample clone() throws CloneNotSupportedException
return (ShallowCloneExample) super.clone();

epoll和polI的区别

1.select模型,使用的是数组来存储Socket连接文件描述符,容量是固定的,需要通过轮询来判断是否发生了10事件
2.pol/模型,使用的是链表来存储Socket连接文件描述符,容量是不固定的,同样需要通过轮询来判断是否发生了10事件
3.epoll模型,epoll和poll是完全不同的,epoll是一种事件通知模型,当发生了10事件时,应用程序才进行10操作,不需要像pol/模型那样主动去轮询

抽象类和接口的区别,类可以继承多个类么,接口可以继承多个接口么,类可以实现多个接口

么?
Interface
在Java中,被关键宇interface 修饰的“类”是接口。接口:是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方
法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。
1.禁止直接为其实例化对象 接口连构造方法都没有,所以,根本不可能为其实例化对象。
2.打破单继承局限(实现伪多重继承) 伪代码: class A implements接口C,接口 D…
3.接口中只能定义静态常量和抽象方法,无论普通类还是抽象类都没有如此严格的要求,因此接口既不能继承普通类也不能继承抽象类。
4.接口只能继承接口,且可以多继承
Abstract Class
1.抽象方法一定包含再抽象类中
2.抽象类不能被实例化
3.抽象类主要就是用来被继承的
.如果一个类继承了这个抽象类,这个类必须重写抽象类中的抽象方法
5.当抽象类A继承抽象类B,抽象类A可以不重写B中的方法,但是一旦抽象类A要是在被C继承继承,那么就一定要在C中重写这个抽象
方法
6.抽象类或者抽象方法一定不能被 final修饰的

描述动态代理的几种实现方式,分别说出相应的优缺点

首先我们要区分两个含义上的静态代理和动态代理。从设计模式上来讲:静态代理和动态代理都属于代理模式。
静态代理模式下,代码本身的适用性受到局限,我们可以说是一种“硬编码“的方式:代理类通过构造函数引用 特定的被代理的类,并在执行被代理类的方法时执行一些代理逻辑,达到扩展的目的,因此静态代理的扩展成本较高,不够具有通用性,而且一定程度的通用必须依赖接口。为了解决静态代理的通用性问题,产生了动态代理模式,动态代理的实现底层我们不会自己去写,通常是使用已有的动态代理技术,在Java生态中,目前普遍使用的是JDK自带的代理和CGLib摆供的类库。
对比:
(1)JDK动态代理实现了被代理对象的接口,CGLib动态代理继承了被代理对象。
(2)JDK动态代理和CGLib 动态代理都在运行期生成字节码,JDK动态代理直接写Class字节码,CGLib 动态代理使用ASM框架写Class字
节码。CGLib动态代理实现更复杂,生成代理类比JDK动态代理效率低。
(3)JDK动态代理调用代理方法是通过反射机制调用的,CGLib动态代理是通过FastClass机制(索引分配直接调用)直接调用方法的,因此
CGLib动态代理的执行效率更高。
开发中,我们不必太过纠结性能问题,可以根据自己的实际需求灵活选择。

(弃用)为什么CGlib方式可以对接口实现代理

讲讲JAVA的反射机制

什么是反射?
反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
反射的主要功能
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时调用任意一个对象的方法,通过反射甚至可以调用到private修饰的方法
·生成动态代理
反射的应用
Spring 框架的10C基于反射创建对象和设置依赖属性。
Spring MVC的请求调用对应方法,也是通过反射。
JDBC的Class.forName(String className)方法,也是使用反射。
反射的优点
1.增加程序的灵活性,避免将程序写死到代码里。
2.可以在程序运行的过程中,操作这些对象。
3.测试时可以利用反射API访问类的私有成员,以保证测试代码覆盖率。
反射的缺点
1.性能问题
a.使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此Java反射机制主要应用在对灵活性和扩展性要求很
高的系统框架上,普通程序不建议使用。
b.反射包括了一些动态类型,所以JVM无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在
经常被 执行的代码或对性能要求很高的程序中使用反射
.使用反射会模糊程序内部逻辑
a.程序人员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂。
3.内部暴露
a.由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用
-一代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。
软件工程没有银弹。很多程序架构,尤其是三方框架,无法保证自己的封装是完美的。如果没有反射,对于外部类的私有成员,我们将一筹莫
展,所以我们有了反射这一后门,为程序设计提供了更大的灵活性。工具本身并没有错,关键在于如何正确地使用。

如何实现不可变的类?

::一个类的对象在通过构造方法创建后如果状态不会再被改变,那么它就是一个不可变(immutable)类。
它的所有成员变量的赋值仅在构造方法中完成,不会提供任何setter方法供外部类去修改。
自从有了多线程,生产力就被无限地放大了,所有的程序员都爱它,因为强大的硬件能力被充分地利用了。但与此同时,所有的程序员都对它
心生忌惮,因为一不小心,多线程就会把对象的状态变得混乱不堪。
为了保护状态的原子性、可见性、有序性,我们程序员可以说是竭尽所能。其中,synchronized(同步)关键字是最简单最入门的一种解决方
案。
假如说类是不可变的,那么对象的状态就也是不可变的。这样的话,每次修改对象的状态,就会产生一个新的对象供不同的线程使用,我们程
序员就不必再担心并发问题了。
要实现一个不可变类,必须要满足以下 4个条件:
1)确保类是 final的,不允许被其他类继承。
2)确保所有的成员变量(字段)是final的,这样的话,它们就只能在构造方法中初始化值,并且不会在随后被修改。
3)不要提供任何setter方法。
如果要修改类的状态,必须返回一个新的对象。

NIO的原理,包括哪几个组件?

NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的1/O模型,也是1/O多路复用的基础,已经被越来越多地应用
到大型应用服务器,成为解决高并发与大量连接、1/0处理问题的有效方式。
•NIO 有三大核心部分:Channel(通道)、Buffer(缓冲区)、Selector(选择器)
•NIO 是面向缓冲区/块编程的。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动,这就增加了处理过程中的灵活性,使
用它可以提供非阳寒式的高伸缩性网络

如何使用在线调试工具Arthas?

什么是 Arthas?
Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问
题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。
通常,本地开发环境无法访问生产环境。如果在生产环境中遇到问题,则无法使用IDE远程调试。更糟糕的是,在生产环境中调试是不可接受
的,因为它会暂停所有线程,导致服务暂停。
开发人员可以尝试在测试环境或者预发环境中复现生产环境中的问题。但是,某些问题无法在不同的环境中轻松复现,甚至在重新启动后就消
失了。
如果您正在考虑在代码中添加一些日志以帮助解决问题,您将必须经历以下阶段:测试、预发,然后生产。这种方法效率低下,更糟糕的是,
该问题可能无法解决,因为一旦JVM重新启动,它可能无法复现,如上文所述。
Arthas旨在解决这些问题。开发人员可以在线解决生产问题。无需JVM重启,无需代码更改。Arthas作为观察者永远不会暂停正在运行的线
程。
Arthas 能做些什么?
1.这个类从哪个jar 包加载的?为什么会报各种类相关的Exception?
2.我改的代码为什么没有执行到?难道是我没commit?分支搞错了?
3.遇到问题无法在线上debug,难道只能通过加日志再重新发布吗?
4.线上遇到某个用户的数据处理有问题,但线上同样无法debug,线下无法重现!
5.是否有一个全局视角来查看系统的运行状况?
6.有什么办法可以监控到JVM的实时运行状态?
7.怎么快速定位应用的热点,生成火焰图?
8.怎样直接从JVM内查找某个类的实例?

http https

在这里插入图片描述

Overload、Override、Overwrite的介绍?

overload 意为重载,override意为覆盖,overwrite意为重写。从中文意思上看,并无差别,但是如下所示,给出英文定义:
Overloading occurs when two or more methods in one class have the same method name but different parameters.
当一个类中的两个或多个方法具有相同的方法名但参数不同时,就会发生重载。
Overriding or overwrite means having two methods with the same method name and parameters (i.e., method signature). One of
the methods is in the parent class and the other is in the child class.
重写意味着有两个方法具有相同的方法名和参数(即方法签名)。其中一个方法在父类中,另一个在子类中。
Overload 为同一个类中,存在多个方法名相同的函数,但是他们拥有不同的参数(参数个数,类型,顺序)。
Override 和Overwrite为子类和父类之间,子类和父类拥有同样的方法名和参数列表,只是将方法体重写。这是面向对象编程的多态性。
Overload 规则
1.包含多个同名函数,但是参数各不相同。
2.参数类型、参数个数、参数顺序(不同类型间)至少有一个不同。
3.可以改变返回值类型(不能作为重载判断依据)
4. 可以改变访问修饰符(不能作为重载判断依据)
5.可以改变异常类型和数量(不能作为重载判断依据)
Overrite 规则
1.存在于子类和父类之间
2.子类必须和父类的方法名和参数列表必须完全相同。
3.可以改变返回值类型,但子类返回值类型必须是父类返回值类型的派生类。
4.可以改变访问修饰符,但是子类权限只能更开放。
5.声明为 final的方法不能被重写
6.声明为static的方法不能被重写,但是可以被重新声明。
7,构造器不能被重写。
8.子类和父类在同一个包中时,子类可以重写父类所有方法(出 private 和 final)
9.子类和父类在不同包中时,子类只能重写父类的public和protected的非final方法。
10.重写可以抛出任何非强制性异常,但是不能抛出新的强制性异常,或者比父类方法更广泛的异常。
在jdk1.5中引入了泛型,泛型的存在是用来解决什么问题
Java 泛型这个特性是从JDK1.5才开始加入的,因此为了兼容之前的版本,Java 泛型的实现采取了“伪泛型”的策略,即Java在语法上支持泛型,但是在编译阶段会进行所谓的“类型擦除”(Type Erasure),将所有的泛型表示(尖括号中的内容)都替换为具体的类型(其对应的原生态类型),就像完全没有泛型一样。
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过
程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

.重载(Overload): 在一个类中,同名的方法如果有不同的参数列表(比如参数类型不同、参数个数不同)则视为重载。
.重写(Override):从字面上看,重写就是重新写一遍的意思。其实就是在子类中把父类本身有的方法重新写一遍。子类继承了父类的方法,但有时子类并不想原封不动的继承父类中的某个方法,所以在方法名,参数列表,返回类型都相同(子类中方法的返回值可以是父类中方法返回值的子类)的情况下,对方法体进行修改,这就是重写。但要注意子类方法的访问修饰权限不能小于父类的。

解决hash冲突的办法有哪些?HashMap用的哪种?

What is Hashing?
SHA
256
1.开放定址法
2.再Hash法+
3.链地址法
4.公共溢出区

你知道哪几种锁?分别有什么特点?

偏向锁/轻量级锁/重量级锁;
可重入锁/非可重入锁;
共享锁/独占锁;
公平锁/非公平锁;
悲观锁/乐观锁;
自旋锁/非自旋锁;
可中断锁/不可中断锁。

在jdk1.5中引入了泛型,泛型的存在是用来解决什么问题

Java 泛型这个特性是从JDK1.5才开始加入的,因此为了兼容之前的版本,Java泛型的实现采取了“伪泛型”的策略,即Java在语法上支持泛型,但是在编译阶段会进行所谓的“类型擦除”(Type Erasure),将所有的泛型表示(尖括号中的内容)都替换为具体的类型(其对应的原生态类型),就像完全没有泛刑一样
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过
程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
·适用于多种数据类型执行相同的代码(代码复用)
泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型)
泛型上下限
为了解决泛型中隐含的转换问题,Java 泛型加入了类型参数的上下边界机制。<?extends A>表示该类型参数可以是 A(上边界)或者A的子类类型。编译时擦除到类型 A,即用 A类型代替类型参数。这种方法可以解决开始遇到的问题,编译器知道类型参数的范围,如果传入的实例类型B是在这个范围内的话允许转换,这时只要一次类型转换就可以了,运行时会把对象当做A的实例看待。

如何理解Java 中的泛型是伪泛型?泛型中类型擦除

Java 泛型这个特性是从JDK1.5才开始加入的,因此为了兼容之前的版本,Java 泛型的实现采取了“伪泛型”的策略,即Java 在语法上支持泛型,但是在编译阶段会进行所谓的“类型擦除”(Type Erasure),将所有的泛型表示(尖括号中的内容)都替换为具体的类型(其对应的原生态类型),就像完全没有泛型一样。理解类型擦除对于用好泛型是很有帮助的,尤其是一些看起来“疑难杂症”的问题,弄明白了类型擦除也就迎刃而解了。
泛型的类型擦除原则是:
消除类型参数声明,即删除<>及其包围的部分。
根据类型参数的上下界推断并替换所有的类型参数为原生态类型:如果类型参数是无限制通配符或没有上下界限定则替换为Object,如果
存在上下界限定则根据子类替换原则取类型参数的最左边限定类型(即父类)。
自动产生“桥接方法”以保证擦除类型后的代码仍然具有泛型的“多态性”。
那么如何进行擦除的呢?
擦除类定义中的类型参数-无限制类型擦除
当类定义中的类型参数没有任何限制时,在类型擦除中直接被替换为Object,即形如和<?>的类型参数都被替换为Object。

有没有可能2个不相等的对象有相同的 hashcode?

·如果两个对象equals,Java 运行时环境会认为他们的hashcode一定相等
如果两个对象不equals,他们的hashcode有可能相等
如果两个对象hashcode相等,他们不一定equals
如果两个对象hashcode 不相等,他们一定不equals
String aa =“Aa”;
String bb =“BB”;
System.out.println(aa.hashCode())
target classes■ org
System.out.println(bb.hashCode());
System.out.println(aa.hashCode()== bb.hashCode());
L beiming>GCopy Tact?

用过哪些Map类,都有什么区别,HashMap 是线程安全的吗,并发下使用的 Map 是什么,他

们内部原理分别是什么,比如存储方式,hashcode,扩容,默认容量等。
有HashMap、HashTable、LinkedHashMap、TreeMap
在Map中插入,删除,定位元素:HashMap
要按照自定义顺序或自然顺序遍历:TreeMap
要求输入顺序和输出顺序相同:LinkedHashMap
从内部数据结构分析:
HashMap 数组+链表/红黑树
HashTable数组+链表
LinkedHashMap 双向链表
TreeMap红黑树
从线程安全分析:
HashMap非线程安全

实际上我们也可以这么理解,就是在JDK7中,使用的是分段锁,在JDK8中使用的是“读写锁”毕竟采用了CAS和Synchronized来保证线
程的安全。

Error 和 Exception的区别,CheckedException,RuntimeException的区别

先搞清楚它们三者的关系。Error与 Exception都继承自Throwable,而RuntimeException 则继承自Exception。在 Java中只有 Throwable
类型的实例才可以被抛出|(throw)或捕获(catch)。
Error 和Exception 体现了Java平台设计者对不同异常情况的分类。Exception是程序正常运行中可以预料的意外情况,可能并且应该被捕获,进行相应处理。Error则是指在正常情况下,不大可能出现的情况,绝大部分的Error 都会导致程序(比如JVM)处于非正常的、不可恢复状态。既然是非正常情况,所以不便于也不需要捕获,常见的比如OutOfMemoryError,其为Error的子类。
再谈谈Checked Exception 与 Runtime Exception 的区别:

  1. Checked Exception 的基类是 Exception;Runtime Exception的基类是 RuntimeException(不过
    是Exception).
  2. Checked Exception 要求必须捕获.一个方法内如果抛出了Checked Exception,必须要么catch,要么给方法声明 throws 以交给上一层去处理,如果漏写了 catch 会直接通不过编译.Runtime Exception 就没这个要求,不强制catch或throws,这样对于明显不会异常的代码段就不必处理了.

什么是阻塞队列?你知道Java中有哪些阻塞队列吗?

Mybatis存在哪些优点和缺点

优点:
1.基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL单独写,解除sql与程序代码的耦合,便于统一管
理。
2.与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接;
3.很好的与各种数据库兼容(因为MyBatis 使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)。
4.能够与Spring很好的集成;
5.提供映射标签,支持对象与数据库的ORM字段关系映射; 提供对象关系映射标签,支持对象关系组件维护。

字符串常量池

字符串常量池的设计思想
1.字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程序的性能
2.JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化
为字符串开辟一个字符串常量池,类似于缓存区
创建字符串常量时,首先查询字符串常量池是否存在该字符串
存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中
三种字符串操作(Jdk1.7及以上版本)
直接赋值字符串
String s=“zhuge”;
1/ s指向常量池中的引用这种方式创建的字符串对象,只会在常量池中。
因为有”zhuge"这个字面量,创建对象s的时候,JVM会先去常量池中通过equals(key)方法,判断是否有相同的对象
如果有,则直接返回该对象在常量池中的引用;
如果没有,则会在常量池中创建一个新对象,再返回引用。
new String();
String s1 = new String(“zhuge"); // s1指向内存中的对象引用
这种方式会保证字符串常量池和堆中都有这个对象,没有就创建,最后返回堆内存中的对象引用。
步骤大致如下。
因为有“zhuge”这个字面量,所以会先检查字符串常量池中是否存在字符串”zhuge²”
不存在,先在字符串常量池里创建一个字符串对象;再去内存中创建一个字符串对象”zhuge";
存在的话,就直接去堆内存中创建一个字符串对象”zhuge”:
最后,将内存中的引用返回。
intern方法
string s1 = new string(“zhuge”);
String s2 = s1.intern();
4 System.out.println(s1 == s2); //false
String中的inter方法是一个native的方法,当调用intem方法时,如果池已经包含一个等于此String对象的字符串(用equals(oject)方法确定),则返回池中的字符串。否则,将intern返回的引用指
向当前字符串s1(jdk1.6版本需要将s1复制到字符串常量池里)。
字符串常量池位置
Jdk1.6及之前:有永久代,运行时常量池在永久代,运行时常量池包含字符串常量池
Jdk1.7:有永久代,但已经逐步“去永久代”,字符串常量池从永久代里的运行时常量池分离到堆里
Jdk1.8及之后:无永久代,运行时常量池在元空间,字符串常量池里依然在堆里
用一个程序证明下字符串常量池在哪里:
4 public class RuntimeconstantPool00m
5
public static void main(string[] args)
ArrayList list = new ArrayListc>();
for (int i =0; i< 100000000; i++){
for (int j =e;j< 1000000;j++){

八种基本类型包装类的常量池是如何实现的

java中基本类型的包装类的大部分都实现了常量池技术(严格来说应该叫对象池,在堆上),这些类是Byte,Short,Integer,Lopg,Character,Boolean,另外两种浮点数类型的包装类则没有实现。另外Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127时才可使用对象池,也即对象不负责创建和管理大于127的这些类的对象。因为一般这种比较小的数用到的概率相对较大。
public class Test
public static void main(String[] args){
1/5种整形的包装类Byte,Short,Integer,Long,Character的对象,
//在值小于127时可以使用对象池
Integer i1 = 127; //这种调用底层实际是执行的Integer.valueOf(127),里面用到了
Integer i2 = 127;
System.out.println(i1 == i2);//输出true
//值大于127时,不会从对象池中取对象
Integer i3 = 128;

//用new关键词新生成对象不会使用对象池Integer i5 = new Integer(127);Integer i6 = new Integer(127);
System.out.println(i5 == i6);//输出false
//Boolean类也实现了对象池技术
Boolean bool1 = true;
Boolean bool2 = true;
System.out.println(bool1 == bool2);//输出true
//浮点类型的包装类没有实现对象池技术
Double dl = 1.0:

Jdk1.7到Jdk1.8 HashMap 发生了什么变化(底层)?

1.1.7中底层是数组+链表,1.8中底层是数组+链表+红黑树,加红黑树的目的是提高HashMap插入和查询整体效率
2.1.7中链表插入使用的是头插法,1.8中链表插入使用的是尾插法,因为1.8中插入key和value时需要判断链表元素个数,所以需要遍历链表统计链表元素个数,所以正好就直接使用尾插法
3.1.7中哈希算法比较复杂,存在各种右移与异或运算,1.8中进行了简化,因为复杂的哈希算法的目的就是提高散列性,来提供HashMap的整体效率,而1.8中新增了红黑
树,所以可以适当的简化哈希算法,节省CPU资源

什么是字节码?采用字节码的好处是什么?

编译器(javac)将Java源文件(*java)文件编译成为字节码文件(“.class),可以做到一次编译到处运行,windows上编译好的class文件,可以直接在linux上运行,通过这种方式做到跨平台,不过Java的跨平台有一个前提条件,就是不同的操作系统上安装的JDK或JRE是不一样的,虽然字节码是通用的,但是需要把字节码解释成各个操作系统的机器码是需要不同的解释器的,所以针对各个操作系统需要有各自的JDK或JRE。
采用字节码的好处,一方面实现了跨平台,另外一方面也提高了代码执行的性能,编译器在编译源代码时可以做一些编译期的优化,比如锁消除、标量替换、方法内联等。

Java中的异常体系是怎样的

Java中的所有异常都来自顶级父类Throwable。
.Throwable下有两个子类Exception和Error。
Error去s非E党严重的错误,Etiava Lano StackoverElowErrorkava Lano OufOtMemorvEfror。通常这些错误出现时,仅仅想靠程序自己是解决不了的,可能是虚拟。

·Java中的所有异常都来自顶级父类Throwable。
·Throwable下有两个子类Exception和Error。
·Error表示非常严重的错误,比如java.lang.StackOverFlowError和Java.lang.OutOfMemoryError,通常这些错误出现时,仅仅想靠程序自己是解决不了的,可能是虚拟
机、磁盘、操作系统层面出现的问题了,所以通常也不建议在代码中去捕获这些Error,因为捕获的意义不大,因为程序可能已经根本运行不了了。
Exception表示异常,表示程序出现Exceptiom时,是可以靠程序自己来解决的,比如NullPointerException、IllegalAccessException等,我们可以捕获这些异常来做特殊
处理。
.Exception的子类通常又可以分为RuntimeExcLption和非RuntimeException两类
·RunTimeException表示运行期异常,表示这个异常是在代码运行过程中抛出的,这些异常是非检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序
逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生,比如NullPointerException、IndexOutOfBoundsException等。
非RuntimeException表示非运行期异常,也就是我们常说的检查异常,是必须进行处理的异常,如果不处理,程序就不能检查异常通过。如IOException、SQLException等以及
用户自定义的Exception异常。

在Java的异常处理机制中,什么时候应该抛出异常,什么时候捕获异常?

异常相当于一种提示,如果我们抛出异常,就相当于告诉上层方法,我抛了一个异常,我处理不了这个异常,交给你来处理,而对于上层方法来说,它也需要决定自己能不
能处理这个异常,是否也需要交给它的上层。
所以我们在写一个方法时,我们需要考虑的就是,本方法能否合理的处理该异常,如果处理不了就继续向上抛出异常,包括本方法中在调用另外一个方法时,发现出现了异
常,如果这个异常应该由自己来处理,那就捕获该异常并进行处理。

TCP的三次握手和四次挥手

TCP协议是7层网络协议中的传输层协议,负责数据的可靠传输。
在建立TCP连接时,需要通过三次握手来建立,过程是:
1.客户端向服务端发送一个SYN
2.服务端接收到SYN后,给客户端发送一个SYN_ACK
3.客户端接收到SYN_ACK后,再给服务端发送一个ACK
在断开TCP连接时,需要通过四次挥手来断开,过程是:
1.客户端向服务端发送FIN
2.服务端接收FIN后,向客户端发送ACK,表示我接收到了断开连接的请求,客户端你可以不发数据了,不过服务端这边可能还有数据正在处理
3.服务端处理完所有数据后,向客户端发送FIN,表示服务端现在可以断开连接
4.客户端收到服务端的FIN,向服务端发送ACK,表示客户端也会断开连接了

说一下HashMap的Put方法

先说HashMap的Put方法的大体流程:
1.根据Key通过哈希算法与与运算得出数组下标
2.如果数组下标位置元素为空,则将key和value封装为Entry对象(JDK1.7中是Entry对象,JDK1.8中是Node对象)并放入该位置
3.如果数组下标位置元素不为空,则要分情况讨论
a,如果是JDK1.7,则先判断是否需要扩容,如果要扩容就进行扩容,如果不用扩容就生成Entry对象,并使用头插法添加到当前位置的链表中
b.如果是JDK1.8,则会先判断当前位置上的Node的类型,看是红黑树Node,还是链表Node
i.如果是红黑树Node,则将key和value封装为一个红黑树节点并添加到红黑树中去,在这个过程中会判断红黑树中是否存在当前key,如果存在则更新value ii.如果此位置上的Node对象是链表节点,则将key和value封装为一个链表Node并通过尾插法插入到链表的最后位置去,因为是尾插法,所以需要遍历链表,在遍历链表的过程中会判断是否存在当前key,如果存在则更新value,当遍历完链表后,将新链表Node插入到链表中,插入到链表后,会看当前链表的节点个数,如果大于等于8,那么则会将该链表转成红黑树
fii.将key和value封装为Node插入到链表或红黑树中后,再判断是否需要进行扩容,如果需要就扩容,如果不需要就结束PUT方法

单例Bean和单例模式

单例模式表示JVM中某个类的对象只会存在唯一—个。
而单例Bean并不表示JVM中只能存在唯一的某个类的Bean对象。

【临渊羡鱼不如退而结网】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值