首页 > 其他分享 >面试题基础

面试题基础

时间:2022-08-26 11:13:57浏览次数:64  
标签:扩容 面试题 hash 树化 基础 链表 Vector 线程

整理了一些基础的面试题

前言

虽然这些面试题已经看了N+1遍了,但是看懂是一回事,组织语言说出来,又是一回事,像我这种嘴笨的一段时间不复习就表达不出来了,照成面试失败or压薪资!!

String、StringBuffer、StringBuilder

1、相同点

这三个类都是用来处理字符串的。

2、是否可变

  • String类型的字符串对象是不可变的,⼀旦String对象创建后,包含在这个对象中的字符系列是不可以改变的,直到这个对象被销毁。
  • StringBuilder和StringBuffer类型的字符串是可变的,不同的是StringBuffer类型的是线程安全的,⽽StringBuilder不是线程安全的

3、使用场景

  • 使⽤String类的场景:
    在字符串不经常变化的场景中可以使⽤String类,例如常量的声明、少量的变量运算。

  • 使⽤StringBuffer类的场景:
    在频繁进⾏字符串运算(如拼接、替换、删除等),并且运⾏在多线程环境中,则可以考虑使⽤StringBuffer,例如XML解析、HTTP参数解析和封装。

  • 使⽤StringBuilder类的场景:
    在频繁进⾏字符串运算(如拼接、替换、和删除等),并且运⾏在单线程的环境中,则可以考虑使⽤StringBuilder,如SQL语句的拼装、JSON封装等。

  • StringBuilder和StringBuffer的“可变”特性总结如下:
    (1)append,insert,delete⽅法最根本上都是调⽤System.arraycopy()这个⽅法来达到⽬的
    (2)substring(int, int)⽅法是通过重新new String(value, start, end - start)的⽅式来达到⽬的。因此,在执⾏substring操作时,StringBuilder和String基本上没什么区别。

    总的来说,三者在执⾏速度⽅⾯的⽐较:
    StringBuilder > StringBuffer > String

方法重写和方法重载

方法重写特点:重写的关键字override

  • 三同一不同:
    • 方法的返回值类型相同
    • 方法名相同
      - 参数列表相同
    • 方法的具体实现是不同的

方法重载:前提:必须是在同一个类中

  • 一同三不同:
    • 方法名必须一致
    • 参数列表不同(参数数据类型不同、参数个数不同)
    • 和访问修饰符、返回值类型无关

抽象类和接口

1、 相同点

都是用来抽取公共的特性的;都不能初始化;都没有构造器

2、定义方式

接口使用interface定义,抽象类使用abstract class定义;

3、 使用方式

一个类可以实现多个接口,但只能继承一个抽象类;

4、 属性

接口里面的属性都是常量,都是使用public static final修饰的,即便没有写也是;抽象类里面可以有普通的类变量;

5、方法

- 接口里面的方法都是抽象方法,即都没有方法体(注意从jdk8之后是可以有的,使用default修饰方法);
- 抽象类里面可以没有抽象方法,也可以有(使用abstract修饰);
- 抽象类可以有构造方法,接口中不能有构造方法;
- 抽象类中可以包含静态方法,接口中不能包含静态方法;

ArrayList、Vector、LinkedList

1、相同点

这三个类都是List的实现,都是有序可重复的集合

2、底层实现

ArrayList和Vector是基于数组的,存放在连续的内存块,LinkedList底层基于双向链表,无需连续内存;
ArrayList和Vector随机查询快(通过索引也就是下标直接访问),尾部插入、删除性能可以,其它部分插入、删除都会移动数据,因此性能会低;
LinkedList随机查询慢(需要基于指针从头一个一个查找,最坏的情况要遍历整个集合才能找到),头尾增删快,随机的话不一定因为要先找对应的数据需要遍历,所以不是绝对的快

3、线程安全性

ArrayList线程不安全,Vector线程安全(使用synchronized关键字锁定方法),然而,Vector性能较低,所以一般不怎么使用(并没有废弃),建议使用下面的方式代替Vector:
Collections.synchronizedList(new ArrayList<>())
new CopyOnWriteArrayList<>()  :写入时复制
CopyOnWrite 比 Vector NB 
Vector里面有synchronized锁效率低   CopyOnWrite用的lock锁

4、LinkedList线程不安全,如果需要使用线程安全的链表List,有两种处理方法:

1. 调用List<String> list = Collections.synchronizedList(new LinkedList<String>());
2. 将LinkedList全部换成ConcurrentLinkedQueue

5、大小以及增长方式

ArrayList 默认大小为0,第一次add的时候会扩容为10,之后每次以1.5倍扩容
Vector 默认就是10 每次扩容以2倍扩容 

HashMap、HashTable、 LinkedHashMap 、ConcurrentHashMap

1、相同点

这三个类都是都是Map的实现,也就是说,都是双列的集合,都是存放键值对的,底层实现都是基于数组+链表的结构,也就是hash表。

2、 底层结构

除了LinkedHashMap之外,都是基于数组+链表的结构,而LinkedHashMap还在此基础上维护了一个双向链表,用来保证元素插入的顺序,所以LinkedHashMap可以保证元素的插入顺序,其他的几个则不可以

3、 null值要求

HashMap的key和值都可以为null;HashTable的键和值都不能为null;ConcurrentHashMap的键和值都不能为null;

4、容量和增长方式

HashMap : 默认大小16,负载因子0.75,当hash表的容量超过负载因子的时候开始扩容,扩容为原始容量的2倍。
HashTable:初始容量为11,负载因子为0.75。超过负载因子容量开始扩容,扩容为旧的容量*2+1。

5、 安全性及性能

HashMap是线程不安全的,所以效率高;HashTable是基于synchronized实现的线程安全的Map,效率较低;
ConCurrentHashMap线程安全,但是锁定的只是一部分代码,所以效率比HashTable高。
从concurrentHashMap的代码可以看出它引入了一个分段锁的概念,具体的可以理解为把一个大的hashmap拆分为n个小的hashtble,根据key.hashcode()来决定把key放到那个hashtable中concurrentHashMap和hashtable的主要区别是围绕着锁的力度如何,可以简单理解为大的hashtable拆分为多个小的,形成了锁分离

HashMap

1、基本数据结构

  • 1.7 数组 + 链表

  • 1.8 数组 + (链表 | 红黑树)

    链表插入节点时,1.7 是头插法,1.8 是尾插法

  • 1.7 是大于等于阈值且没有空位时才扩容,而 1.8 是大于阈值就扩容

  • 1.8 在扩容计算 Node 索引时,会优化

2、树化与退化

树化意义

  • 红黑树用来避免 DoS 攻击,防止链表超长时性能下降,树化应当是偶然情况,是保底策略
  • hash 表的查找,更新的时间复杂度是 $O(1)$,而红黑树的查找,更新的时间复杂度是 $O(log_2⁡n )$,TreeNode 占用空间也比普通 Node 的大,如非必要,尽量还是使用链表
  • hash 值如果足够随机,则在 hash 表内按泊松分布,在负载因子 0.765 的情况下,长度超过 8 的链表出现概率是 0.00000006,树化阈值选择 8 就是为了让树化几率足够小

树化规则

当链表长度超过树化阈值 8 时,先尝试扩容来减少链表长度,如果数组容量已经 >=64,才会进行树化

退化规则

  • 情况1:在扩容时如果拆分树时,树元素个数 <= 6 则会退化链表
  • 情况2:remove 树节点时,若 root、root.left、root.right、root.left.left 有一个为 null ,也会退化为链表

3、索引计算

索引计算方法

  • 首先,计算对象的 hashCode()
  • 再进行调用 HashMap 的 hash() 方法进行二次哈希
    • 二次 hash() 是为了综合高位数据,让哈希分布更为均匀
  • 最后 & (capacity – 1) 得到索引

数组容量为何是 2 的 n 次幂

  • 计算索引时效率更高:如果是 2 的 n 次幂可以使用位与运算代替取模
  • 扩容时重新计算索引效率更高: hash & oldCap == 0 的元素留在原来位置 ,否则新位置 = 旧位置 + oldCap

注意

  • 二次 hash 是为了配合 容量是 2 的 n 次幂 这一设计前提,如果 hash 表的容量不是 2 的 n 次幂,则不必二次 hash
  • 容量是 2 的 n 次幂 这一设计计算索引效率更好,但 hash 的分散性就不好,需要二次 hash 来作为补偿,没有采用这一设计的典型例子是 Hashtable

4、put 与扩容

put 流程

  • HashMap 是懒惰创建数组的,首次使用才创建数组
  • 计算索引(桶下标)
  • 如果桶下标还没人占用,创建 Node 占位返回
  • 如果桶下标已经有人占用
    • 已经是 TreeNode 走红黑树的添加或更新逻辑
    • 是普通 Node,走链表的添加或更新逻辑,如果链表长度超过树化阈值,走树化逻辑-
  • 返回前检查容量是否超过阈值,一旦超过进行扩容

扩容(加载)因子为何默认是 0.75f

在空间占用与查询时间之间取得较好的权衡
  • 大于这个值,空间节省了,但链表就会比较长影响性能
  • 小于这个值,冲突减少了,但扩容就会更频繁,空间占用也更多

JAVA有哪些数据类型

JAVA数据类型分为基本数据类型和引用数据类型
  • 基本数据类型有四类八种:
  • 整型:byte(1字节)、short(2字节)、int(4字节)、long(8字节)
  • 浮点型:float(4字节)、double(8字节)
  • 字符型:char(2字节)
  • 布尔型:boolean(1位)
  • 引用类型:类class、接口interface、数组[]

标签:扩容,面试题,hash,树化,基础,链表,Vector,线程
From: https://www.cnblogs.com/yanzhong/p/16626896.html

相关文章

  • Spring Boot 2.x基础教程:EhCache缓存的使用
    在SpringBoot中通过@EnableCaching注解自动化配置合适的缓存管理器(CacheManager),SpringBoot根据下面的顺序去侦测缓存提供者:GenericJCache(JSR-107)(EhCache3,Haze......
  • Python基础——迭代器 生成器
    迭代器iterator迭代简单理解就是重复,但是每次重复产生的结果还要作为下次重复的初始值。可迭代对象:含有——iter——方法的对象。可以用for...in..遍历的都是可迭代对......
  • 1. mongodb基础:cursor.forEach使用
    varxtdb_db=connect("ip:port/实例名").getSisterDB("xtdb");varback_db=connect("ip:port/实例名").getSisterDB("xtdb_del_back");xtdb_db.auth("username","pass......
  • 面试题:Java序列化与反序列化
    目录序列化和反序列化的概念应用场景?序列化实现的方式继承Serializable接口,普通序列化继承Externalizable接口,强制自定义序列化serialVersionUID的作用静态变量不会被序列......
  • 学习笔记:github的基础使用复习_流畅使用技巧
    笔记内容来自网站up主小迷糊。包括以下两个视频链接: 『教程』手把手教你流畅访问Github_哔哩哔哩_bilibili『教程』一看就懂!Github基础教程_哔哩哔哩_bilibili1、关于......
  • JavaScript基础回顾知识点记录7-事件补充说明2
    js中鼠标滚轮事件offsetWidth/offsetHeight-对象的可见宽度/高度clientWidth/clientHeight-内容的可见宽度/高度scrollWidth/scrollHeight......
  • Docker 基础(一)
    Docker笔记Docker为什么比VM快Docker有着比虚拟机更少的抽象层。Docker利用的是宿主机的内核,VM需要GuestOS。Docker常用命令帮助命令dockerversion#......
  • RabbitMQ 入门系列:5、基础编码:交换机的进阶介绍及编码方式。
    系列目录RabbitMQ入门系列:1、MQ的应用场景的选择与RabbitMQ安装。RabbitMQ入门系列:2、基础含义:链接、通道、队列、交换机。RabbitMQ入门系列:3、基础含义:持久化......
  • vue3 基础-生命周期函数
    在vue中,生命周期函数可理解为"在某个时刻,会自动执行的函数".先直观感受一下图示.一共就八个:<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-......
  • python3 的基础数据类型
    python有六种基本的数据类型,分别是:Numbers数字String字符串List列表Tuple元组Set集合(python3新增)Dictionary字典在这六个基本数据中可变数据类型为:list,set,dict......