2020JAVA春招基础知识(1)

由于最近一直在忙着春招实习的事情,所以想写一篇帖子来记录下整个过程中遇到的面经,也当是一个自我复习的过程,话不多少,开始吧。
1.Set,List,Map介绍一下
List是一个包含重复数据,并且有序的一个集合,提供了按照索引来访问的方式
Set是一个不可重复且无序的集合
Map是按照键值对存储的,键不可重复,并且支持键值都为null的情况
2.HashMap链表转红黑树是怎么实现的
hashmap在jdk1.8之前底层结构都是数组+链表的形式,但是1.8之后改为了数组+链表+红黑树的形式,当链表的长度大于阈值(默认为8)并且整个map中键值对的个数大于64时,链表会自动转为红黑树,否则只会进行扩容操作。首先它会将整个链表中的节点转为树节点,之后通过比较每个树节点hash值大小来确定插入左子树还是右子树,最后调整整个树,使之符合红黑树的特点
3.JDK中消费者生产者应用场景
线程池实现任务的处理或者直接使用消息队列
4.Synchronized和ReentrantLock
Synchronized是java中的关键字,可以通过它进行加锁操作,它可以修饰类,方法和代码块,Synchronized发生异常时会自动释放锁,它是一种不可响应中断的锁同时也是一种非公平的锁
ReentrantLock实现了Lock接口,它只能对代码块进行加锁操作,它是一种可响应中断的锁,相对于Synchronized来说,它可以设置成公平锁(默认是非公平的),同时它也可以通过绑定多个Condition对象来实现等待或者唤醒的功能,相比于Synchronized,它可以准确地唤醒某一个线程
总的来说,如果是线程竞争不怎么激烈的情况下,推荐使用Synchronized,因为系统会对Synchronized去尽可能的优化,但是在竞争激烈的情况下,Synchronized的性能会急剧下降,这时就该ReentrantLock登场了
PS:为什么Synchronized在竞争激烈的情况下性能会急剧下降呢?这牵扯到操作系统从用户态转到核心态上,这一过程会非常消耗性能
5.servlet怎么响应浏览器请求
首先服务器接收到请求之后会交给相应的容器去处理,这时容器会先创建两个对象,分别为Request对象和Response对象,之后会创建一个新的线程并将这两个对象以参数的形式传递过去,然后容器调用对应的servlet的service()方法去处理请求,处理结束之后会销毁之前的对象
6.ArrayList的resize
首先针对当前数组长度和所需数组长度相比较,若当前数组小于所需数组长度则进行扩容操作,将当前数组扩容1.5倍,之后将原数组的数据复制到新数组中去。
7.Spring bean初始化过程
spring源码
invokeAwareMethods源码
在这里插入图片描述
以AbstractAutowireCapableBeanFactory为例,通过调用initializeBean方法去对bean进行初始化,首先调用invokeAwareMethods方法去对bean进行setBeanName,setBeanClassLoader和setBeanFactory,之后调用applyBeanPostProcessorsBeforeInitialization方法,这时就应该初始化我们的bean了,如果指定了初始化方法则会被调用,最后一步调用invokeInitMethods,在这个方法里分别调用了afterPropertiesSet方法和invokeCustomInitMethod方法。
简单的来说:
1.bean实例化
2.设置属性值
3.如果实现了BeanNameAware接口则调用setBeanName方法
4.如果实现了BeanClassLoaderAware接口则调用setBeanClassLoader方法
5.如果实现了BeanFactoryAware接口则调用setBeanFactory方法
6.调用postProcessBeforeInitialization方法
7.如果自定义了init方法则该方法会被执行,在这个方法中会先执行afterPropertiesSet方法,再去执行init方法
8.如果没有自定义的init方法,则调用invokeInitMethods方法,在这个方法中先执行afterPropertiesSet方法,再执行默认的init方法。
8.TCP三次握手
第一次握手:当客户端与服务器端建立HTTP连接时,首先会发送连接请求
第二次握手:服务器端收到连接请求之后将响应消息返回给客户端
第三次握手:客户端收到响应之后再次发送连接确认请求
9.进程通信方式
管道
信号
共享内存
消息队列
信号量
套接字
10.进程线程区别
进程是系统进行资源调度和分配的单位,一个系统至少有一个进程
线程是CPU进行资源调度和分配的单位,一个进程至少有一个线程
进程拥有独立的内存空间,而线程则是共享进程的内存空间
11.Java HashMap底层实现
hashmap是通过hash算法来确定存取数据的一种数据结构,它通过put()方法来存数据,get()方法来取数据。在调用put()方法时,首先计算出key的hash值,然后在通过这个去确定存储的位置,如果位置上已经有元素了,那么就出现了hash冲突。hashmap采用了链地址法去解决这个问题,也就是把hashcode相同的元素存放到链表中,除了链地址法还有再hash法(通过构造多个不同的hash函数,出现冲突时改用别的hash函数去再计算一次,直到不产生冲突为止),开放定址法(以计算出来的hashcode为基础在进行一次hash算法去计算得到第二个hashcode,往复循环直到不冲突为止)等方法。在调用get()方法取值时,根据key去计算出hash值,然后确定位置,如果该位置上存在链表,也就是对应多个元素,那么就要调用equals方法去确定取的到底是哪一个元素了。
在jdk1.8之前出现hash冲突往链表中插入元素使用了头插法,jkd1.8则改为了尾插法,这是因为使用头插法会在hashmap进行扩容的时候形成循环链表。
12.tcp如何保证安全可靠
1.数据包校验,通过校验包对传输的数据进行校验,一旦出错则丢弃报文段并不给出响应
2.对失序数据包进行排序
3.丢弃重复数据
4.应答机制,当一端收到数据时会发送一个应答给另一端
5.超时重发:当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段
6.流量控制,TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据,这可以防止较快主机致使较慢主机的缓冲区溢出,这就是流量控制
13.数据库三大范式
第一范式:要求数据库表的每一列都是不可分割的原子数据项。
举例:一列中只能存储一种数据在这里插入图片描述
这里家庭信息明显不符合,应该讲家庭信息字段拆成多个字段
第二范式:在1NF的基础上,非码属性必须完全依赖于候选码
第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)
在这里插入图片描述
这里的订单金额和订单时间明显和产品号无关,所以不符合第二范式
第三范式:在2NF基础上,任何非主属性不依赖于其它非主属性
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关
在这里插入图片描述
这里班主任性别和班主任年龄都是和班主任姓名相关而和主键无关,不符合第三范式
14.http与https的区别
1.http与https的端口不同,http的端口是80,而https是443
2.资源消耗不同,由于https需要加解密,所以会更加消耗资源
3.https需要证书,而证书一般是需要去认证机构购买的。
既然提到了加解密,那么就说一下对称加密和非对称加密
对称加密是使用公钥加解密,在传输过程需要将公钥发送给对方,这样安全性就比较差
非对称加密是通过公钥加密私钥解密,发送方使用对方的公钥进行加密,接受方收到数据后使用自己的私钥进行解密,安全性比较高,但是会比较耗资源
15.Mysql的存储引擎
这里主要介绍两种主流引擎,一种是Innodb另一种是Myisam
Innodb:Mysql5.5之后默认的存储引擎,支持事务操作,行锁和外键
Myisam:Mysql5.5之前默认的储存引擎,不支持事务操作
总的来说,Myisam适合查询比较频繁的场景,因为它的查询效率高于Innodb,而Innodb适合于修改频繁和对安全性要求较高的场景
行锁和表锁:
表锁两种存储引擎都支持,当你在进行数据库操作时,条件语句中的字段不带索引时会进行全表检索,这时就需要对整张表加锁
行锁是Innodb才有的,当你进行查询时,匹配的条件字段带有索引,这时就需要用到行锁
16.谈一谈一下BIO,NIO,AIO
BIO:同步阻塞IO,传统的IO,我们一般使用的IO就是BIO,它的特点是一个连接一个线程,不管这个连接有没有做事
NIO:同步非阻塞IO,它与BIO相比,采用了通道的复用技术,使用单线程的选择器去管理通道,并且利用缓冲区去存取数据,它的特点是一个请求一个线程,使用一个线程去处理多个客户端的连接请求,使用selector去轮询通道获取是否有IO操作(关键词:buffer,channel,selector)
AIO:异步非阻塞IO,相比于同步,异步不会将线程一直等待IO操作的发生,而是当IO操作发生会去通知相对应的线程来处理
17.说一下JVM的内存结构
1.程序计数器(线程私有):用来记录当前线程所执行字节码的行号
2.虚拟机栈(线程私有):用来描述方法的内存模型,每个方法执行时都会创建一个栈帧,用来存放局部变量表,操作数栈等信息,方法的调用到结束对应着栈帧的入栈和出栈操作
3.本地方法栈(线程私有):与虚拟机栈的作用类似,只不过虚拟机栈是为了jvm调用java方法服务的,而本地方法栈则是为了调用本地方法服务的
4.方法区(线程共有):存放加载到jvm的类信息,常量,静态变量等
5.堆(线程共有):存放创建的对象
18.线程之间的通信方式
1.使用volatile关键字
2.使用wait/notify
3.使用CountdownLatch
19.FULLGC,MinorGC在什么条件下会发生
MinorGC:Eden区满了或者Eden所剩空间小于新创建对象的大小
FullGC:之前晋升对象的平均大小大于老年代剩余空间大小或者MinorGC之后剩余存活对象大小大于老年代剩余空间大小
20.Redis的数据结构
Redis是一种存储键值对的数据结构,它的键只支持String类型,而值支持五种类型,分别是String,List,Set,Zset和Hash
21.类加载机制
提到类加载机制,不得不说到双亲委派模型
在这里插入图片描述
如上图所示就是双亲委派模型,该模型的含义为:当一个类加载器收到类加载命令时,不会马上调用类加载器而是会询问父类加载器,因此所有的类加载请求最终都会送到位于顶层的启动类加载器处,只有当父类加载器反馈无法加载时,子类加载器才会去尝试加载
那么会不会出现破坏双亲委派模型的情况呢?这是会的,因为双亲委派模型只是一种推荐的模型,并不是强制性的。如果出现了启动类中存在调用用户代码的情况下,那么该模型的层次结构就被打破了,这样一来,双亲委派模型就被破坏了。
22.Redis缓存一致性
Redis作为一种缓存的机制,必然会面临到缓存一致性的问题,最终的解决方案是为缓存数据设置过期时间,到了时间之后就直接去数据库中查询数据并存到缓存中去
23.Redis容灾策略
1.为每个master节点配置一个slave节点,当master节点宕机了那么slave节点自动升级为master节点
2.备份迁移
例如,假设集群有三个主节点 A,B,C。节点 A 和 B 都各有一个从节点,A1 和 B1。节点 C 有两个从节点:C1 和 C2。
主节点 A 失效。A1 被提升为主节点。
节点 C2 迁移成为节点 A1 的从节点,要不然 A1 就没有任何从节点。
三个小时后节点 A1 也失效了。
节点 C2 被提升为取代 A1 的新主节点。
集群仍然能继续正常工作。
24.Spring中的IOC和AOP
AOP:面向切面编程,在OOP编程中,我们一般只能从上到下的进行开发,而对于那些水平分散在各个业务逻辑代码中的公共操作却无法统一定义,而AOP则是为了解决这种问题,比如日志操作,可以通过定义Aspect类来规定日志的操作,在业务中直接去调用就可以了而不需要重复性地去写代码
IOC:控制反转,在不使用Spring的情况下,我们一般新建对象都是通过new的形式,这样实例化对象的控制权是由程序控制的,而对于IOC来说,它将这种权利交给了容器去处理
25.JAVA中几种引用类型
1.强引用,只要存在强引用,那么被引用的对象不会被回收
2.软引用,若在下一次垃圾回收之前内存不足的话,那么该对象就会被回收
3.弱引用,不管内存够不够,在下一次的垃圾回收都会被回收掉
4.虚引用,该引用并没有什么作用,只是当该对象被回收时会收到一个系统通知而已
27.Spring中的动态代理
一般分为两种,一种是JDK动态代理,一种是CGLIB动态代理
JDK动态代理:JDK动态代理的前提是,需要被代理的类必须是一个接口。首先通过Proxy类创建一个代理对象,之后再通过InvocationHandler去对代理对象中的方法进行增强
在这里插入图片描述
CGLIB动态代理:对指定的目标类生成一个子类,并覆盖其中方法实现增强,所以对于那些不是接口的类,推荐使用CGLIB动态代理
在这里插入图片描述
28.分布式环境做线程同步
1.一台服务器作为中间服务器,剩余服务器需要进行线程同步的操作全部转到中间服务器上进行加锁,排队的操作
2.利用数据库做分布式锁,首先建一张方法表并在方法字段上加上唯一索引,对于需要同步的方法,每次操作时都往数据库插入一条数据,当多个线程都想要执行方法时,由于唯一索引的缘故,只能有一个线程获得执行权,方法结束之后把对应插入的数据删除掉
3.利用Redis做分布式锁,首先利用UUID创建一个String字符串作为value,再利用SETNX方法为当前锁设置一个value,value值就为创建的UUID值,之后利用expire()方法为这个锁设置超过时间,一旦超过这个时间锁会自动释放避免死锁,最后通过对比UUID的值去释放锁

来自于:https://www.jianshu.com/p/9055ca856aaf

29.ConcurrentHashMap线程安全的方式转换
这是一种线程安全的HashMap,它位于juc包下,Jdk1.8之前它使用分段锁的形式来保证线程同步安全,1.8之后改为了CAS+Synchronized的形式,下面来说说每种形式的特点
分段锁:见名知意,将数据分段,给每一段上加锁,这样的话当一个线程来访问数据的时候并不会对整个数据加锁,然后只对需要的那部分数据加锁,只要不是访问同一段数据段就可以达到很好的性能。分段锁的核心就是被称为Segment的可重入锁,它的结构和HashMap很相似,都是数组+链表的形式。ConcurrentHashMap里面有一个Segment数组,每一个Segment里面有包含了一个HashEntry数组,每个HashEntry是一个链表结构的元素,结构如下
在这里插入图片描述
CAS+Synchronized:在谈及CAS+Synchronized之前,我们先回到分段锁,上面说了分段锁是将每个不同的数据段加锁,这样的话只要不是多个线程同时访问同一个数据段就不会出现线程同步的问题,这里锁的细化是到达了每一个segment,而对于CAS+Synchronized来说,它将锁的粒度更加细微,针对链表中的每一个节点进行加锁操作,这种情况下,除非是多个线程访问同一个节点,注意是同一个节点不是同一个链表,那么就不会出现线程同步的情况。还有一种情况就是就算真的出现了线程竞争,那么对于Synchronized的来说,只要在自旋的时候能够重新获得锁,那么线程就不会被挂起,而segment由于继承了ReentrantLock,它只会在重新尝试一次就会被挂起,这样一来我们会遇到大量的上下文切换从而导致性能的下降
30.tcp四次挥手,第四次挥手时一直丢包了怎么办
此问题可以引申到tcp连接中某段出现异常那么另一端怎么知晓呢。首先HTTP具有一个功能,叫做KeeAlive,对应的就是长短连接
短连接:每次请求都会建立一条连接,请求结束之后连接马上关闭
长连接:第一次请求之后建立的连接不会随着第一次请求结束而马上关闭,之后的请求可以复用该连接,只会在最后的时候关闭连接
相应的,TCP中也存在一种称之为KeepAlive的功能,它主要是通过保活计时器去实现的,当通信双方因为某些原因造成了异常连接时,可能某一端并不知晓,那么保活计时器就发挥它的作用了, 它会在相同的时间间隔内发送数据,一共发送9次(默认9次),若这9次都没有收到响应就会把该连接断掉

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值