2021JAVA基础面试题(持续更新中...)

1.java1.7到1.8HashMap底层发生了什么变化

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

2.Jdk1.7到1.8java虚拟机发生了什么变化

  • 1.7中存在永久代,1.8中没有永久代,替换它的是元空间,源空间所占的内存不是虚拟机内部,而是本地内存空间,这么做的原因是,不管是永久代还是元空间,他们都是方法区的具体实现,之所以元空间所占的内存搞成本地内存,官方的说法是为了和JRockit统一,其次方法去所存储的类信息通常比较难确定,所以对于方法区的大小比较难指定,太小了容易出现方法区溢出,太大了又会占用太多虚拟机的内存空间,而转移到本地内存后则不会影响虚拟机所占用的内存

3.Java中的异常体系

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

4.String、StringBuffer与StringBuilder之间区别

  • String是final修饰,不可变,每次操作都会产生新对象
  • StringBuffer和StringBuilder都是在原对象上操作
  • StringBuffer是线程安全的,StringBuilder线程不安全
  • 性能:StringBuilder>StringBuffer>String
  • 场景:经常需要改变字符串内容时优先使用StringBuilder,多线程使用共享变量时使用StringBuffer

5.ArrayList和LinkList有哪些区别

  • 底层数据结构不同,ArrayList底层是基于数组实现,LinkList底层基于链表实现
  • 两者查询时间复杂度都为O(N),但是由于底层数据结构的不同,ArrayList更适合随机查找,LinkList更适合删除和添加。
  • 另外ArrayList和LinkedList都实现了List接口,但是LinkedList还额外实现了Deque接口,所以LinkedList还可以当做队列来使用

6.ConcurrentHashMap 1.7和1.8的区别

  • 整体结构变化:

    1.7:Segment + HashEntry + Unsafe

    1.8: 移除Segment,使锁的粒度更小,Synchronized + CAS + Node + Unsafe

  • put()方法变化:

    1.7:先定位Segment,再定位桶,put全程加锁,没有获取锁的线程提前找桶的位置,并最多自旋64次获取锁,超过则挂起。

    1.8:由于移除了Segment,类似HashMap,可以直接定位到桶,拿到first节点后进行判断,1、为空则CAS插入;2、为-1则说明在扩容,则跟着一起扩容;3、else则加锁put(类似1.7)

  • get()方法变化:

    基本类似,由于value声明为volatile,保证了修改的可见性,因此不需要加锁。

  • resize()方法变化:

    1.7:跟HashMap步骤一样,只不过是搬到单线程中执行,避免了HashMap在1.7中扩容时死循环的问题,保证线程安全。

    1.8:支持并发扩容,HashMap扩容在1.8中由头插改为尾插(为了避免死循环问题),ConcurrentHashmap也是,迁移也是从尾部开始,扩容前在桶的头部放置一个hash值为-1的节点,这样别的线程访问时就能判断是否该桶已经被其他线程处理过了。

  • size()方法变化:

    1.7:很经典的思路:计算两次,如果不变则返回计算结果,若不一致,则锁住所有的Segment求和。

    1.8:用baseCount来存储当前的节点个数,这就设计到baseCount并发环境下修改的问题

7.接口及抽象类的区别

  • 抽象类可以存在成员函数,而接口中只能存在public abstract方法
  • 抽象类中的成员变量可以是各种类型,接口中的成员变量只能输public abstract final类型
  • 抽象类是单继承,接口可以多实现
  • 接口设计的目的是对类的约束行为,也就是提供一种机制,可以强制要求不同的类具有相同的行为,它只约束了行为的有无,但是不对如何实现进行限制
  • 抽象类的设计目的是代码复用,当不同的类具有某些相同的行为,且且其中一部分行为的实现方式一致时可以让这些类都派生出一个抽象类。
  • 使用场景:当关注一个事物的本质的时候用抽象类,当关注一个操作的时候用接口 

备注:笔者在整理过程中可能存在答案错误,欢迎各位码农留言纠错

        

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值