【大厂面试合集每日一刷——3. 阿里巴巴2022Java工程师春招真题

2023年 7月 19日 42.1k 0

每日一句

在这里插入图片描述

每日一刷

考试时间 100min

1. HashMap的底层原理? HashMap怎么扩容? HashMap是线程安全的吗?

回答:在jdk1.7之前HashMap是基于数组和链表实现的,而且采用头插法。

而jdk1.8 之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间。采用尾插法。

HashMap默认的初始化大小为 16。当HashMap中的元素个数之和大于负载因子*当前容量的时候就要进行扩充,容量变为原来的 2 倍。(这里注意不是数组中的个数,而且数组中和链/树中的所有元素个数之和!)

注意:我们还可以在预知存储数据量的情况下,提前设置初始容量(初始容量 = 预知数据量 / 加载因子)。这样做的好处是可以减少 resize() 操作,提高 HashMap 的效率
美团面试的时候问到这个问题,还给出具体的值,让我算出初始值设置为多少合适?

HashMap是线程不安全的,其主要体现:

1.在jdk1.7中,在多线程环境下,扩容时会造成环形链或数据丢失。

2.在jdk1.8中,在多线程环境下,会发生数据覆盖的情况。

追问:HashMap扩容的时候为什么是2的n次幂?

回答:数组下标的计算方法是(n - 1) & hash,取余(%)操作中如果除数是2的幂次则等价于与其除数减一的与(&)操作(也就是说 hash%length==hash&(length-1)的前提是 length 是2的 n 次方;)。” 并且 采用二进制位操作 &,相对于%能够提高运算效率,这就解释了 HashMap 的长度为什么是2的幂次方。

追问:HashMap的put方法说一下。

回答:通过阅读源码,可以从jdk1.7和1.8两个方面来回答

1.根据key通过哈希算法与与运算得出数组下标

2.如果数组下标元素为空,则将key和value封装为Entry对象(JDK1.7是Entry对象,JDK1.8是Node对象)并放入该位置。

3.如果数组下标位置元素不为空,则要分情况

​ (i)如果是在JDK1.7,则首先会判断是否需要扩容,如果要扩容就进行扩容,如果不需要扩容就生成Entry对象,并使用头插法添加到当前链表中。

(ii)如果是在JDK1.8中,则会先判断当前位置上的TreeNode类型,看是红黑树还是链表Node

​ (a)如果是红黑树TreeNode,则将key和value封装为一个红黑树节点并添加到红黑树中去,在这个过程中会判断红黑树中是否存在当前key,如果存在则更新value。

​ (b)如果此位置上的Node对象是链表节点,则将key和value封装为一个Node并通过尾插法插入到链表的最后位置去,因为是尾插法,所以需要遍历链表,在遍历过程中会判断是否存在当前key,如果存在则更新其value,当遍历完链表后,将新的Node插入到链表中,插入到链表后,会看当前链表的节点个数,如果大于8,则会将链表转为红黑树

​ ©将key和value封装为Node插入到链表或红黑树后,在判断是否需要扩容,如果需要扩容,就结束put方法。

追问:HashMap源码中在计算hash值的时候为什么要右移16位?

回答:我的理解是让元素在HashMap中更加均匀的分布,具体的可以看下图,下图是《阿里调优手册》里说的。

在这里插入图片描述

2.说一下ConcurrentHashMap?
回答:在jdk1.7是 分段的数组+链表 ,jdk1.8的时候跟HashMap1.8的时候一样都是基于数组+链表/红黑树。

ConcurrentHashMap是线程安全的

(1)在jdk1.7的时候是使用分段所segment,每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。

(2)在jdk1.8的时候摒弃了 Segment的概念,而是直接用 Node 数组+链表+红黑树的数据结构来实现,并发控制使用 synchronized 和 CAS 来操作。synchronized只锁定当前链表或红黑二叉树的首节点。

3.Https和Http的区别?
1、HTTP 是超⽂本传输协议,信息是明⽂传输,存在安全⻛险的问题。HTTPS 则解决 HTTP 不安全的缺陷,在TCP 和 HTTP 网络层之间加了 SSL/TLS 安全协议,使得报⽂能够加密传输。

2、HTTP 连接建立相对简单, TCP 三次握手之后便可进行 HTTP 的报文传输。而HTTPS 在 TCP 三次握手之后,还要进行 SSL/TLS 的握⼿过程,才可进⼊加密报文传输。

3、HTTP 的端口号是 80,HTTPS 的端口号是 443。

4、 HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的

4.访问一个网址时域名发生了什么过程?
总体来说分为以下几个过程:

  • DNS解析
  • TCP连接
  • 发送HTTP请求
  • 服务器处理请求并返回HTTP报文
  • 浏览器解析渲染页面
  • 连接结束
  • 在这里插入图片描述

    5.乐观锁和悲观锁知道吗?
    悲观锁和乐观锁并不是某个具体的“锁”而是一种并发编程的基本概念。乐观锁和悲观锁最早出现在数据库的设计当中,后来逐渐被 Java 的并发包所引入。

    悲观锁:认为对于同一个数据的并发操作,一定是会发生修改的,哪怕没有修改,也会认为修改。因此对于同一个数据的并发操作,悲观锁采取加锁的形式。悲观地认为,不加锁的并发操作一定会出问题。

    乐观锁:正好和悲观锁相反,它获取数据的时候,并不担心数据被修改,每次获取数据的时候也不会加锁,只是在更新数据的时候,通过判断现有的数据是否和原数据一致来判断数据是否被其他线程操作,如果没被其他线程修改则进行数据更新,如果被其他线程修改则不进行数据更新。

    6.Spring中AOP是怎么实现的?
    AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib ,这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理

    追问 Spring中Bean的初始化过程?
    这块建议看一下Spring的源码就比较清楚了。

    在这里插入图片描述

    7.Spring中IOC?
    IOC:IOC是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spring框架来管理。负责创建对象,使用依赖注入(dependency injection,DI)管理它们,将对象集中起来,配置对象,管理对象的整个生命周期。

    IOC的好处有哪些?
    IOC或依赖注入最小化应用程序代码量。
    它使测试应用程序变得容易,因为单元测试中不需要单例或JNDI查找机制。
    以最小的代价和最少的干扰来促进松耦合。
    IOC容器支持快速实例化和懒加载。

    7.JVM的内存模型?
    Java的运行时区主要包含堆、方法区、虚拟机栈、程序计数器和本地方法栈,其中堆和方法区是所有线程所共有的。而且虚拟机栈、程序计数器和本地方法栈是线程所私有的。

    堆:存放对象实例

    方法区:用来存储已经被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

    虚拟机栈:(生命周期与线程相同)Java中每个方法执行的时候,Java虚拟机都会同步创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。

    程序计数器:保存下一条需要执行的字节码指令,是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都是依赖程序计数器。

    本地方法栈:与虚拟机栈类似

    8.sleep和wait有什么区别?
    (1)sleep方法属于Thread类,wait方法属于Object类

    (2)sleep方法暂停执行指定的时间,让出CPU给其他线程,但其监控状态依然保持在指定的时间过后又会自动恢复运行状态。

    (3)在调用sleep方法的过程中,线程不会释放对象锁,而wait会释放对象锁。

    wait为什么是数Object类下面的方法?

    这个问题我被问到过两次,第一次不会(美团),就去百度搜了搜,第二次遇到就会了(贝壳),下面是网上搜到的。

    所谓的释放锁资源实际是通知对象内置的monitor对象进行释放,而只有所有对象都有内置的monitor对象才能实现任何对象的锁资源都可以释放。又因为所有类都继承自Object,所以wait()就成了Object方法,也就是通过wait()来通知对象内置的monitor对象释放,而且事实上因为这涉及对硬件底层的操作,所以wait()方法是native方法,底层是用C写的。【来自网络】

    9.创建线程的方式有哪些?
    Java中创建线程的方式有4种,分别是

    (1)写一个类继承子Thread类,重写run方法

    (2)写一个类重写Runable接口,重写run方法

    (3)写一个类重写Callable接口,重写call方法

    (4)使用线程池

    追问:使用Callable()创建线程比另外两种方式有什么优势吗?

    10.怎么调整堆的大小?要修改哪个参数?
    初始值-Xms和最大值-Xmx

    11.用Linux命令查看当前有哪些进程在活跃呢?
    Linux查看进程命令:PS命令

    ps命令是一个相当强大地Linux进程查看命令.运用该命令可以确定有哪些进程正在运行和运行地状态、 进程是否结束、进程有没有僵死、哪些进程占用了过多地资源等等.总之大部分信息均为可以通过执行该命令得到地。

    PS命令语法:
    ps [选项]
    -e 显示所有进程,环境变量
    -f 全格式
    -h 不显示标题
    -l 长格式
    -w 宽输出
    -a 显示终端上地所有进程,包括其他用户地进程
    -r 只显示正在运行地进程
    -x 显示没有控制终端地进程
    

    PS命令使用:

    ps命令用于查看当前正在运行的进程,常用的方法是ps aux,然后再通过管道使用grep命令过滤查找特定的进程,再对特定的进程进行操作,其中grep起到搜索作用。

    例如:

    ps -ef | grep java
    

    表示查看所有进程里 CMD 是 java 的进程信息

    ps -aux | grep java
    

    -aux 显示所有状态

    通常用 ps 查看进程 PID ,用 kill 命令终止进程,如:

    例如:

     kill -9 [PID]
    

    -9 表示强迫进程立即停止

    Linux查看进程命令:Top命令

    top命令可以实时显示各个线程情况。要在top输出中开启线程查看,请调用top命令的“-H”选项,该选项会列出所有Linux线程。在top运行时,你也可以通过按“H”键将线程查看模式切换为开或关。

    12.用Linux查看文件有哪些命令?
    (1)目录管理命令
    ——ls:列出指定目录下的内容
    格式:ls [OPTION]… [FILE]…
    -a:显示所有文件包括隐藏文件
    -A:显示除.和…之外的所有文件
    -l,–long:显示文件的详细属性信息
    -h:对文件大小进行单位换算,可能影响精度
    -d:查看目录本身而非其内部的文件
    -r:逆序显示文件
    -R:递归显示文件

    示例:ls -lah / --详细显示/目录下的所有文件(包括隐藏文件)
       ls -ldh /etc --详细显示/etc目录本身
       ls -lhv / --倒序显示/目录下所有文件(包括隐藏文件)
       ls -R /etc    --递归显示/etc下所有文件
    

    ——mkdir:创建目录
    格式:mkdir [OPTION]… DIRECTORY…
    -p:自动按需创建父目录
    -m:创建目录时给定权限

    示例:mkdir -p /data/test/A/B --在/data目录下递归创建/test/A/B三个目录
       mkdir -m 711 -p /data/MODE/A --在/data目录下递归创建MODE/A两个目录同时指定目录A的权限为711
    

    ——rmdir:删除目录
    格式:rmdir [OPTION]… DIRECTORY…
    -p:删除目录后如果其父目录为空,则一并删除

    示例:rmdir -p /data/test/A --删除A目录后,test目录为空,一并删除
    

    ——cd:切换目录

    示例:cd ..:切换到上级目录
       cd ~:切换回自己的家目录
       cd -:在上一次目录与当前目录直接来回切换
    

    ——pwd:显示当前目录
    (2)文件管理命令
    ——cp:复制
    格式:单源复制:cp [OPTION]… [-T] SOURCE DEST(如果DEST不存在则创建,存在则覆盖)
    多源复制:cp [OPTION]… SOURCE… DIRECTORY(DEST必须为directory)
    -i:交互式复制,即覆盖前提醒用户确认
    -f:强制覆盖目标文件
    -r,-R:递归复制目录

    示例:cp -if /data/[1-3].txt /data/test --test必须为目录,把三个文件一起复制到test中
       cp -r /data /practice --把data目录及目录下的内容一起复制到practice中
    

    ——mv:剪切
    格式:单源复制:mv [OPTION]… [-T] SOURCE DEST(如果DEST不存在则创建,存在则覆盖)
    多源复制:mv [OPTION]… SOURCE… DIRECTORY(DEST必须为directory)
    -i:交互式复制,即覆盖前提醒用户确认
    -f:强制覆盖目标文件

    示例:mv -i /data/[1-3].txt /practice --把/data目录下三个txt文件剪切到/practice下
    

    ——rm:删除
    格式:rm [OPTION]… FILE…
    -i:交互式复制,即覆盖前提醒用户确认
    -f:强制覆盖目标文件
    -r,-R:递归处理,将制定目录下的所有文件包括目录一并删除

    示例:rm -rf /practice --递归删除/practice目录
    

    (3)文本内容管理命令
    ——cat:正向查看文本内容
    格式:cat [OPTION]… [FILE]…
    -n:给显示的文本行编号
    -E:显示行结束符号$

    示例:cat -n /etc/fstab --查看/etc/fatab内容并显示行号
    

    ——tac:倒叙查看文本内容
    格式:tac [OPTION]… [FILE]…

    示例:tac /etc/passwd --倒叙查看文本内容
    

    ——head:显示文本内容,默认显示头10行
    格式:head [OPTION]… [FILE]…
    -n #:显示文本头#行内容

    示例:head -5 /etc/passwd --显示/etc/passwd文件头5行内容
    

    ——tail:显示文本内容,默认显示后10行
    格式:tail [OPTION]… [FILE]…
    -n #:显示文本后#行内容
    -f:查看文件尾部内容结束后不退出,跟随显示新增的行

    示例:tail -8 /etc/passwd --显示/etc/passwd文件后8行内容
    

    ——more:分屏显示文本内容,每次显示一屏显示完停止
    格式:more [options] file […]
    Space键:显示文本下一屏内容
    Enter键:只显示文本下一行内容
    b键:显示文本上一屏内容
    q键:退出
    ——less:分屏显示文本内容,不主动退出
    格式:less [options] file […]
    Space键:显示文本下一屏内容
    Enter键:只显示文本下一行内容
    b键:显示文本上一屏内容
    q键:退出

    13.Redis有哪些应用场景?
    Redis是基于C语言编写的,而且是内存中的数据库,读写速度很快。在项目中也经常会使用Redis,一般会用来做缓存、或者分布式锁,也可以来设计消息队列,同时还支持事务 、持久化、Lua 脚本、多种集群方案。

    14.你用Redis有哪些场景?使用的是哪些数据结构?
    常见的有五种基本数据类型和三种特殊数据类型,

    基本数据结构:String、 list、set、zset和hash,三种特殊数据类型:位图(bitmaps) 、计数器(hyperloglogs)和地理空间(geospatial indexes)。

    String:一般常用在需要计数的场景,比如用户的访问次数、热点文章的点赞转发数量等等。

    list:发布与订阅或者说消息队列、慢查询。

    hash:系统中对象数据的存储。

    set:需要存放的数据不能重复以及需要获取多个数据源交集和并集等场景

    zset:需要对数据根据某个权重进行排序的场景。比如在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息。

    相关文章

    服务器端口转发,带你了解服务器端口转发
    服务器开放端口,服务器开放端口的步骤
    产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
    如何使用 WinGet 下载 Microsoft Store 应用
    百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
    百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

    发布评论