【面试深度解析】掌上先机后端面试(Java基础能力夯实)

欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术的推送!

在我后台回复 「资料」 可领取编程高频电子书
在我后台回复「面试」可领取硬核面试笔记

文章导读地址:点击查看文章导读!

感谢你的关注!

文章目录

  • 掌上先机后端面试(Java基础能力夯实)
    • 题目分析
      • 1、对于 SQL 优化的理解
      • 2、left join 和 exists 的区别和使用场景
      • 3、left join 和 inner join 的区别
      • 4、查找在 A 表中存在,在 B 表中不存在的记录用什么比较好?
      • 5、说说 ArrayList 和 LinkedList 区别
      • 6、ArrayList 扩容的过程
      • 7、它们两个适用的场景
      • 8、ArrayList 和 LinkedLisst 怎么变成线程安全
      • 9、Collections 加锁的原理
      • 10、了解哪些设计模式?
      • 11、写一个懒汉式单例
      • 12、synchronized 能加在哪些地方?
      • 13、volatile 不是直接保证可见性了,为啥还要 DCL?
      • 14、聚簇索引和非聚簇索引的区别
      • 15、回表什么时候会发生?

掌上先机后端面试(Java基础能力夯实)

题目分析

1、对于 SQL 优化的理解

SQL 优化的目的就是让查询速度变快,也就是让 SQL 查询尽量走索引,来优化查询速度

那么常用的一般就是最左前缀原则和覆盖索引

  • 最左前缀原则:表示在联合索引的情况下, 让 where 语句中的条件遵循最左前缀原则,来让 SQL 语句可以走索引
  • 覆盖索引:让 select 中的字段都为索引字段,那么就不需要二次回表查询,大幅提高 SQL 查询速度

还有其他的一些 SQL 优化,比如 order by 的优化,也就是让 where 语句的条件 + order by 语句的条件结合起来符合最左前缀原则,那么也是会走索引的

还有 in 和 exists 的优化,这两个关键字都是对两个表进行筛选数据的,原则就是小表驱动大表,先过滤掉大部分的数据,只留下一小部分数据再去另一个表中做筛选,速度肯定是比拿着很多的数据去另一个表中做筛选要快很多的!

上边我主要说了从哪些方面可以对 SQL 进行优化,具体的细节这里先不写了(比较多),如果需要的话可以找我领取《面试突击》的 pdf 文档,里边都有解析。

2、left join 和 exists 的区别和使用场景

先说一下这两个的区别:

  • left join 是连表查询,会返回左边表的所有数据,如果右表有匹配的记录则显示右表中对应的记录,如果右表中没有匹配的记录,则右表对应的列全部为 Null
  • exists 是一种子查询,返回 true 或 false,用于判断在另一个表中是否有对应的记录,但是并不需要这些记录的具体内容

适用场景:

  • left join 适用于需要保留左表中的全部记录,并且只关心右表中匹配的行记录的情况,但是如果使用 left join 处理大量数据时,可能会有性能问题
  • exists 适用于判断某个条件是否满足,也就是某些记录在另一个表中是否存在,并不关心这些记录的具体内容是什么

这里给出 exists 的使用示例,以及使用建议:

当 A 表的数据集小于 B 表的数据集时,使用 exists

将主查询 A 的数据放到子查询 B 中做条件验证,根据验证结果(true 或 false)来决定主查询的数据是否保留

select * from A where exists (select 1 from B where B.id = A.id)

3、left join 和 inner join 的区别

两者的区别:

  • join 和 inner join 是相同的,inner join 可以简写为 join,表示两个表的交集
  • left join 是左连接,以左表为主,查询左表所有数据,显示右表与左表相关联部分的数据

图示:

有如下两个表:Table A 和 Table B,使用 left join 和 inner join 区别如图所示:

在这里插入图片描述

4、查找在 A 表中存在,在 B 表中不存在的记录用什么比较好?

通过使用 left join 和 not exists 就可以实现

  • LEFT JOIN

使用 left join 的话,对 A 和 B 两个表联表查,如果 B 表中的字段为 null 说明在 B 表中不存在

select A.* from A left join B on A.id=B.id where B.id is null
  • NOT EXISTS

使用 not exists 的话,子查询不为空的话,表示 A 表的数据在 B 表中存在,再通过 not exists 取反即可

select A.* from A where not exists (select 1 from B where A.id = B.id)

性能表现:

  • 使用 left join 时,如果 A 表数据量比较大,B 表数据量比较小时,性能表现较好
  • 使用 not exists 时,如果 A 表数据量比较小,B 表数据量比较大时,性能表现较好

5、说说 ArrayList 和 LinkedList 区别

ArrayList 底层是基于 数组 实现的,而 LinkedList 底层是基于 双向链表 实现的 ,这里主要说一下数组和链表的一些区别即可,区别主要表现在访问、插入、删除这三个操作上:

在这里插入图片描述

  • 对于插入元素和删除元素的性能来说
    • LinkedList 要好一些,如果在头尾插入元素时间复杂度为 O(1),如果在指定位置插入元素,那么时间复杂度是 O(n)
    • 而向 ArrayList 中间插入元素时,需要将后边的元素都向后移动一位,时间复杂度为 O(n)
  • 是否支持快速访问
    • ArrayList 可以根据下标快速访问元素,时间复杂度 O(1)
    • LinkedList 不可以快速访问元素,需要遍历链表,时间复杂度 O(n)

综上,可以发现 LinkedList 和 ArrayList 相比,没有太大优势,一般在项目中不会使用 LinkedList

6、ArrayList 扩容的过程

ArrayList 底层是基于数组实现的,是动态数组,那么它的大小也是动态变化的,这里我说一下扩容的流程:

当添加元素时,发现容量不足,则对数组进行扩容,大小扩容为原来的 1.5 倍,int newCapacity = oldCapacity + (oldCapacity >> 1),通过位运算进行扩容后容量的计算(位运算比较快)

ArrayList 会创建一个新的数组,表示扩容后的数组,将旧数据全部复制到新数组中去,再让 ArrayList 中的数组引用指向新的数组即可

7、它们两个适用的场景

一般不会使用 LinkedList,而是会选择 ArrayList,因为 LinkedList 如果向中间插入元素的话,复杂度也是 O(N) 的(需要先遍历找到要插入的位置),所以相比于 ArrayList 来说并没有太大的优势

8、ArrayList 和 LinkedLisst 怎么变成线程安全

这里主要说一下 ArrayList,LinkedList 的原理也是类似的

要保证 ArrayList 的线程安全,有两种方法:

  • 使用 Collections.synchronizedList
    • 这种方法比较简单粗暴,生成的集合中所有的操作都是通过 synchronized 来保证线程安全的
  • 使用 CopyOnWriteArrayList
    • 这种方法会在每次修改数据时,创建一个新的数据副本,在新数据上进行修改
    • 对于读操作来说,如果数据修改完毕,数组指针指向了新数组,那就可以读到最新数据;如果数据没有修改完毕,数组指针还是指向就数组,那么读取的还是旧数据

适用场景和性能表现:

  • 对于 Collections.synchronizedList 来说,由于读操作是直接读,不需要额外的操作,而写操作需要复制一份新的副本,读操作远远快于写操作,因此它适用于读多写少的场景
  • 对于 CopyOnWriteArrayList 来说,由于所有操作都是通过 synchronized 来保证同步的,读和写的加锁后性能都差不多,因此它适用于读和写比较平均的场景

9、Collections 加锁的原理

Collections.synchronizedList 的原理就是给所有的操作都包装上了一层 synchronized 来保证操作是同步的

注意事项:

通过 Collections.synchronizedList 保证线程安全时,如果使用迭代器 Iterator 来遍历列表的时候,需要手动添加 synchronized 来保证线程安全,在 for each 的时候,也需要手动添加 synchronized 来保证线程安全,因为 for each 的底层也是通过 Iterator 来实现的

// Iterator
synchronized (list) {Iterator i = list.iterator(); // Must be in synchronized blockwhile (i.hasNext())// ...
}
// for each
synchronized (list) {for (Integer i : list) {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(i + ",");}
}

10、了解哪些设计模式?

可以说一说你自己了解到的设计模式,比如单例模式、工厂模式、适配器模式、代理模式,这些都是比较常见的

像在 Spring 中的话,单例模式、工厂模式、代理模式都有使用

在 Spring MVC 中用到了适配器模式

还有 Netty 中的责任链模式

MQ 中的

11、写一个懒汉式单例

  • 线程不安全的懒汉式单例

懒汉式单例也就是在真正需要使用这个对象的时候再去加载这个单例对象,通过 static 来保证这个对象是唯一的

public class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}
  • 线程安全的懒汉式单例

当然上边写出的懒汉式单例还存在 线程安全 的问题,当多个线程同时来创建的时候,可能会创建多个单例对象,因此需要通过 synchronized 和 volatile 来进一步优化,synchronized 保证线程间的同步,将单例对象声明为 volatile 禁止指令重排

public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}

volatile 禁止指令重排

这里的指令重排是指底层硬件为了提升执行效率,对指令进行重排序,比如在上边的代码中 instance = new Singleeton() ,这一行代码对应的字节码有 3 个核心步骤:先创建一个 Singleton 对象、调用 Singleton 的初始化方法、将 Singleton 对象的引用赋值给 instance 变量

那么一般初始化方法的执行速度是比较慢的,可能会被重排序,排到后边去,指令重排序前后对比如下:

在这里插入图片描述

如果发生了指令重排,单线程环境下下是不会有问题的

但是在多线程环境下,第一个线程执行将 Singleton 的引用赋值给 instance 了,但是此时还没有执行完 Singleton 的初始化方法, 如果第二个线程进来,拿到这个 instance 变量,使用了这个未初始化完毕的 Singleton 实例对象,从而导致一些问题出现

12、synchronized 能加在哪些地方?

synchronized 加在不同的地方上,对应锁住的对象也是不同的,那么相对的锁粒度也是不同的

在具体使用中,要注意锁粒度越大,并发度就越低

  • synchronized 加在方法上,锁的是 this 对象

比如创建一个在 Phone 对象的方法加上 synchronized 锁,如果创建 Phone phone = new Phone() 对象,那么锁定的就是这一个 phone 实例对象

class Phone {public synchronized void sendSMS() throws Exception {System.out.println("--------sendSMS");}public synchronized void sendEmail() throws Exception {System.out.println("--------sendEmail");}public void getHello() {System.out.println("---------getHello");}
}
  • synchronized 加在静态方法上,锁的是Class对象,也就是字节码对象

加在静态方法上,锁定 Class 对象,这个锁的粒度就相比于锁定实例对象要大了

因为实例对象可以创建多个,而 Class 对象在 JVM 运行期间,只有一份

class Phone {public static synchronized void sendSMS() throws Exception {System.out.println("--------sendSMS");}
}
  • synchronized 保证同步代码块同步执行,可以自己执行加锁对象
// 使用对象作为锁
public void someMethod() {synchronized (lockObject) {// 需要同步的代码}
}
// 使用类的 Class 对象作为锁
public void someMethod() {synchronized (MyClass.class) {// 需要同步的静态代码}
}

13、volatile 不是直接保证可见性了,为啥还要 DCL?

我们还是先列出来 DCL(双端检锁)的代码:

if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}
}

给 instance 变量加上 volatile 是保证了 instance 变量的原子性,如果不使用 DCL 的话,如下,假设多个线程同时进入到 synchronized 代码块中,那么第一个线程拿到锁,进来初始化 instance 变量,之后释放锁,第二个线程再拿到锁,进来之后他并不知道 instance 变量已经被初始化了,于是又初始化了一下,违背了单例模式

if (instance == null) {synchronized (Singleton.class) {instance = new Singleton();}
}

14、聚簇索引和非聚簇索引的区别

这个是 MySQL 中基础的内容了,不多赘述了

  • 聚簇索引:在聚簇索引中,数据行的物理存储顺序与索引中的顺序相同。换句话说,聚簇索引决定了表中数据的物理存储顺序。每个表只能有一个聚簇索引,通常是由主键自动创建。在InnoDB存储引擎中,聚簇索引的叶子节点直接包含行数据
  • 非聚簇索引:非聚簇索引(也称为二级索引或辅助索引)与聚簇索引不同,它在索引结构中存储的是 索引键值和指向数据行的指针(在InnoDB中通常是主键值)。非聚簇索引的叶子节点不包含实际的数据行,而是包含指向数据行的引用。一个表可以有多个非聚簇索引。

15、回表什么时候会发生?

当使用 SQL 查询时,如果走了索引,但是要查询的列并不全在索引上,因此还需要回表查询完整的数据

在非聚簇索引中,叶子节点保存的是主键的值,如果查询走的非聚簇索引,但是要查询的数据不只有主键的值,还有其他值,此时在非聚簇索引中拿到主键值,还需要再去聚簇索引回表查询,根据主键值查询到整行数据

  • 聚簇索引和非聚簇索引如下,这里画图比较简略了
    • 根据非聚簇索引查询的话,是通过普通的索引字段进行判断的(比如在 name 上建立索引,那就是通过 name 字段去非聚簇索引上进行查询)
    • 根据聚簇索引查询的话,是通过主键进行判断的,直接从 SQL 语句中拿到主键值或者从非聚簇索引中拿到主键值,去聚簇索引中进行查询

请添加图片描述

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/250619.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

01-Java工厂模式 ( Factory Pattern )

工厂模式 Factory Pattern 摘要实现范例 工厂模式(Factory Pattern)提供了一种创建对象的最佳方式 工厂模式在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象 工厂模式属于创建型模式 摘要 1. 意图 …

AJAX的原理(重点)

◆ XMLHttpRequest 什么是XMLHttpRequest? 定义: 关系:axios 内部采用 XMLHttpRequest 与服务器交互 注意:直白点说就是axios内部就是封装了XMLHttpRequest这个对象来实现发送异步请求的 使用 XMLHttpRequest 步骤&#xff1a…

【lesson2】定长内存池的实现

文章目录 介绍定长内存池的设计定长内存池的实现需要成员变量需要的成员函数定长内存池结构定长内存池Delete(释放空间)的实现定长内存池New(申请空间)的实现 定长内存池的实现完整版 介绍 作为程序员(C/C)我们知道申请内存使用的…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Gauge组件

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Gauge组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Gauge组件 数据量规图表组件,用于将数据展示为环形图表。 子组件 无…

【机器学习】科学库使用手册第2篇:机器学习任务和工作流程(已分享,附代码)

本系列文章md笔记(已分享)主要讨论人工智能相关知识。主要内容包括,了解机器学习定义以及应用场景,掌握机器学习基础环境的安装和使用,掌握利用常用的科学计算库对数据进行展示、分析,学会使用jupyter note…

LabVIEW叶片厚度远程监控

LabVIEW叶片厚度远程监控 随着网络技术的高速发展,远程监控广泛应用在各个领域。本文介绍了一种基于LabVIEW的植物叶片厚度远程监控系统,旨在实现对植物生长状况的精准监测和分析。 该系统利用LabVIEW软件开发工具,通过TCP网络协议实现数据…

[嵌入式系统-6]:龙芯1B 开发学习套件 -3-软件层次架构

目录 一、龙芯软件架构 1.1 通用软件架构 1.2 龙芯软件架构 1.3 龙芯各种应用程序 1.4 龙芯SOC芯片硬件:龙芯1B 1.5 PMON软件 1.6 龙芯IDE管辖的软件 (1)CPU Core驱动程序 (2)SOC芯片外设驱动程序 &#xff…

近期CCF系列会议截稿时间

专属领域会议订阅 关注{晓理紫},每日更新会议信息,如感兴趣,请转发给有需要的同学,谢谢支持 如果你感觉对你有所帮助,请关注我,每日准时为你推送最新会议信息。 CSFW (CCF B) IEEE Computer Security Foun…

opencv-python计算视频光流

光流基本概念 光流表示的是相邻两帧图像中每个像素的运动速度和运动方向。具体:光流是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系&#xf…

RISC-V指令格式

RISC-V指令格式 1 RISC-V指令集命名规范2 RISC-V指令集组成2.1 基础整数指令集2.2 扩展指令集 3 RISC-V指令格式3.1 指令表述3.2 指令格式 本文属于《 RISC-V指令集基础系列教程》之一,欢迎查看其它文章。 1 RISC-V指令集命名规范 前面提到过RV32I,这是…

谷粒商城【成神路】-【4】——分类维护

目录 1.删除功能的实现 2.新增功能的实现 3.修改功能的实现 4.拖拽功能 1.删除功能的实现 1.1逻辑删除 逻辑删除:不删除数据库中真实的数据,用指定字段,显示的表示是否删除 1.在application.yml中加入配置 mybatis-plus:global-config:…

基于springboot校园二手书交易管理系统源码和论文

在Internet高速发展的今天,我们生活的各个领域都涉及到计算机的应用,其中包括乐校园二手书交易管理系统的网络应用,在外国二手书交易管理系统已经是很普遍的方式,不过国内的管理系统可能还处于起步阶段。乐校园二手书交易管理系统…

WebAssembly002 FFmpegWasmLocalServer项目

项目介绍 https://github.com/incubated-geek-cc/FFmpegWasmLocalServer.git可将音频或视频文件转换为其他可选的多媒体格式,并导出转码的结果 $ bash run.sh FFmpeg App is listening on port 3000!运行效果 相关依赖 Error: Cannot find module ‘express’ …

《Linux软件编程》的初步认识

一,Linux的认知: Linux 实际上来说是操作系统的内核,ubuntu是操作系统(包括redhat,centos,freebsd等) Linux(操作系统化的内核): 1.管理CPU 2.管理内存 3.管理硬…

基于WordPress开发微信小程序2:决定开发一个wordpress主题

上一篇:基于WordPress开发微信小程序1:搭建Wordpress-CSDN博客 很快发现一个问题,如果使用别人的主题模板,多多少少存在麻烦,所以一咬牙,决定自己开发一个主题模板,并且开源在gitee上&#xff…

redis 6.x集群搭建

redis6集群搭建 安装文件下载 redis-6.2.6.tar.gz 编译 tar -zxvf redis-6.2.6.tar.gz cd redis-6.2.6/ make MALLOClibc make install PREFIX/opt/soft/redis复制可执行文件 cp /opt/soft/redis/redis-cli /usr/bin/redis-cli cp /opt/soft/redis/redis-server /usr/bi…

2024 Flutter 重大更新,Dart 宏(Macros)编程开始支持,JSON 序列化有救

说起宏编程可能大家并不陌生,但是这对于 Flutter 和 Dart 开发者来说它一直是一个「遗憾」,这个「遗憾」体现在编辑过程的代码修改支持上,其中最典型的莫过于 Dart 的 JSON 序列化。 举个例子,目前 Dart 语言的 JSON 序列化高度依…

2024 年, Web 前端开发趋势

希腊哲学家赫拉克利特认为,变化是生命中唯一不变的东西。这句话适用于我们的个人生活、行业和职业领域。 尤其是前端开发领域,新技术、开发趋势、库和框架不断涌现,变化并不陌生。最近发生的一些事件正在改变开发人员构建网站和 Web 应用的方…

Vue2+ElementUI 弹窗全局拖拽 支持放大缩小

拖拽组件 dialogDrag.vue <template><div></div> </template> <script>export default {name: dialogDrag,data() {return {originalWidth: null,originalHeight: null}},created() {this.$nextTick(()>{this.dialogDrag()})},mounted() {}…

业务流程自动化平台在制造业应用案例,助力业务自动化、智能化

捷昌驱动成立于2000年&#xff0c;并于2018年9月在上海证券交易所上市&#xff0c;是一家专注于线性驱动产品研发、生产及销售的科技集团。 公司整合全球资源&#xff0c;为智慧办公、医疗康护、智能家居、工业自动化等关联产业提供驱动及智能控制解决方案&#xff0c;以科技驱…