9月面试总结

本文最后更新于:1 年前

面试的问题都记录在下面,以及问题的一些解答。

Java 基础

谈谈你对 HashMap 的理解

  • HashMap 是以数组+链表的方式存储的;

  • HashMap 存储的是键值对映射,即 key-value;

  • HashMap 可以接受 null 键和 null 值;

  • HashMap 的键如果出现冲突,会以链表的方式链接到后面;

  • HashMap 的链表会一直增长,在 JDK 1.8 中,当链表的长度大于 8 时,将使用红黑树代替。

JVM 有哪些数据区

  • 主要有五个区域: 堆、方法区、虚拟机栈、本地方法栈、程序计数器

说说JVM 运行过程

  • 向操作系统申请空闲内存。系统查找内存分配表,然后把内存段的起始地址和终止地址给JVMJVM准备加载类文件。

  • 给堆、栈分配内存。

  • 文件检查和分析 class 文件。

  • 加载类。(类加载机制,如双亲委派机制)

  • 执行方法。

  • 释放内存。

Java 中的锁机制有哪些

常见的锁有 synchronizedvolatile

synchronized

  • 当使用 synchronized 修饰类普通方法时,那么当前加锁的级别就是实例对象,当多个线程并发访问该对象的同步方法、同步代码块时,会进行同步。

  • 当使用 synchronized 修饰类静态方法时,那么当前加锁的级别就是类,当多个线程并发访问该类(所有实例对象)的同步方法以及同步代码块时,会进行同步。

  • 当使用 synchronized 修饰代码块时,那么当前加锁的级别就是 synchronized(X) 中配置的 x 对象实例,当多个线程并发访问该对象的同步方法、同步代码块以及当前的代码块时,会进行同步。

  • 使用同步代码块时要注意的是不要使用 String 类型对象,因为 String 常量池的存在,所以很容易导致出问题。

volatile

  • volatile 可以看做是一种 synchronized 的轻量级锁,它能够保证并发时,被它修饰的共享变量的可见性,从 jmm 的角度来看一下,每个线程拥有自己的工作内存,实际上线程所修改的共享变量是从主内存中拷贝的副本,当一个共享变量被 volatile 修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。

说说你知道的设计模式

常用的设计模式有单例模式、工厂模式、代理模式、观察者模式、装饰模式、享元模式等

单例模式

  • 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

  • 实现方式通常有两种,分别是 饿汉式单例模式懒汉式单例模式

工厂模式

  • 为创建一组相关或相互依赖的对象提供一个接口,而且无须指定它们的具体类。

  • 一个调用者想创建一个对象,只要知道其名称就可以了。

  • 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。

  • 屏蔽产品的具体实现,调用者只关心产品的接口。

代理模式

  • 代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是生活中常见的中介。

  • 代理模式主要有两个作用:中介隔离,开闭原则

  • 主要有两种代理模式,分别是静态代理和动态代理

观察者模式

  • 定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

  • 观察者模式是一个比较特殊的设计模式,它定义了触发机制,观察者只要订阅了被观察者,就可以第一时间得到被观察者传递的信息。

  • 在工作中,使用观察者模式的场景也比较多,比如消息队列消费等等。

装饰模式

  • 装饰模式在一些类与类之间有叠加效应(也就是给一个类增加附加功能)的场景中非常好用,它可以说是继承的替代品,有更好的扩展性,也比较灵活。在 Java JDK 源码中也大面积用到了装饰模式,比如:java.io.BufferedInputStream(InputStream)

享元模式

  • 享元模式合理提高了对象的复用性,减少了程序的内存占用,还有一个提高性能的地方就是减少了对象创建的过程。

Spring 框架

SpringIOC 理解

  • IOC 就是控制反转,是指创建对象的控制权的转移,以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到 Spring 容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。DI 依赖注入,和控制反转是同一个概念的不同角度的描述,即应用程序在运行时依赖 IoC 容器来动态注入对象需要的外部资源。

  • 最直观的表达就是,IOC 让对象的创建不用去 new 了,可以由 spring 自动生产,使用 java 的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法的。

SpringAOP 理解

  • 一般称为面向切面,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”( Aspect ),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。

  • AOP 实现的关键在于代理模式,AOP代理主要分为静态代理和动态代理。静态代理与动态代理区别在于生成 AOP 代理对象的时机不同。

  • AOP 中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理

Spring 框架中都用到了哪些设计模式?

  • 工厂模式:BeanFactory 就是简单工厂模式的体现,用来创建对象的实例;

  • 单例模式:Bean 默认为单例模式;

  • 代理模式:SpringAOP 功能用到了 JDK 的动态代理和 CGLIB 字节码生成技术;

  • 模板方法:用来解决代码重复的问题。比如 RestTemplateJmsTemplateJpaTemplate

  • 观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现–ApplicationListener。

Spring 事务的实现方式和实现原理

  • Spring 事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring 是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过 bin log 或者 redo log 实现的。

  • Spring 支持编程式事务管理和声明式事务管理两种方式:编程式事务管理使用 TransactionTemplate ;声明式事务管理建立在 AOP 之上的。其本质是通过 AOP 功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

Spring Boot 框架

为什么要用 Spring Boot

  • Spring Boot 可以做到独立运行、简化配置、自动配置、无代码生成和 XML 配置、应用监控、上手容易等优点。

Mybatis 框架

#{}${} 的区别是什么?

  • #{} 是预编译处理,${} 是字符串替换。

  • Mybatis 在处理 #{} 时,会将 sql 中的 #{} 替换为 ? 号,调用 PreparedStatementset 方法来赋值;

  • Mybatis 在处理 ${} 时,就是把 ${} 替换成变量的值。

  • 使用 #{} 可以有效的防止 SQL 注入,提高系统安全性。

Mybatis 的常用标签有哪些?

  • 常用的有 <select><insert><update><delete><resultMap>

通常一个 Xml 映射文件,都会写一个 Dao 接口与之对应,请问,这个 Dao 接口的工作原理是什么?Dao 接口里的方法,参数不同时,方法能重载吗?

  • 接口的全名,就是映射文件中的 namespace 的值;

  • 接口的方法名,就是映射文件中 MapperStatementid 值;

  • 接口方法内的参数,就是传递给 sql 的参数。

  • Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为 key 值,可唯一定位一个 MapperStatement。在 Mybatis 中,每一个 <select><insert><update><delete> 标签,都会被解析为一个 MapperStatement 对象。

  • Mapper 接口里的方法,是不能重载的,因为是使用全限名+方法名的保存和寻找策略;

  • Mapper 接口的工作原理是 JDK 动态代理,Mybatis运行时会使用 JDK 动态代理为 Mapper 接口生成代理对象 proxy,代理对象会拦截接口方法,转而执行MapperStatement所代表的sql,然后将sql执行结果返回。

Mybatis 是如何将 sql 执行结果封装为目标对象并返回的?都有哪些映射形式?

  • 第一种是使用 <resultMap> 标签,逐一定义数据库列名和对象属性名之间的映射关系。

  • 第二种是使用 sql 列的别名功能,将列的别名书写为对象属性名。

  • 有了列名与属性名的映射关系后,Mybatis 通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。

如何获取自动生成的(主)键值?

  • 可以在 <insert> 内加上 usegeneratedkeys=”true” keyproperty=”id”(假设主键名称为id)

Mybatis一对一、一对多的关联查询是用什么标签实现的?

  • 主要是通过 <association>, <collection> 来实现的

Redis

Redis 支持哪些数据类型?

  • 支持的有 String, Hash, List, Set, zset, 压缩列表等

什么是 Redis 持久化?Redis有哪几种持久化方式?优缺点是什么?

  • 持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。

  • Redis 提供了两种持久化方式: RDB(默认)和 AOF

  • RDB 持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是 fork 一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。

  • RDB 持久化会清除原有的存储结构,只将数据存储到磁盘中。当需要从磁盘还原数据到内存的时候,再重新将数据组织成原来的数据结构。

  • AOF 持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。

  • AOF 持久化会保留原来的存储格式,将数据按照原有的格式存储在磁盘中。拿散列表这样的数据结构来举例。可以将散列表的大小、每个数据被散列到的槽的编号等信息,都保存在磁盘中。有了这些信息,从磁盘中将数据还原到内存中的时候,就可以避免重新计算哈希值。

  • AOF文件比RDB更新频率高,优先使用AOF还原数据。

  • AOFRDB更安全也更大

  • RDB性能比AOF

  • 如果两个都配了优先加载AOF

什么是缓存穿透?如何避免?什么是缓存雪崩?何如避免?

  • 一般的缓存系统,都是按照 key 去缓存查询,如果不存在对应的 value,就应该去后端系统查找(比如DB)。一些恶意的请求会故意查询不存在的 key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透

  • 避免的方法:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该 key 对应的数据 insert 了之后清理缓存。对一定不存在的 key 进行过滤;可以把所有的可能存在的 key放到一个大的Bitmap中,查询时通过该Bitmap过滤。

  • 当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压力。导致系统崩溃。这就叫做缓存雪崩

  • 避免的方法:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个 key 只允许一个线程查询数据和写缓存,其他线程等待;做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2A1缓存失效时间设置为短期,A2设置为长期;不同的 key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

MySQL

数据库事务的四个特性

  • ACID

  • 原子性(Atomicity):指的是事务中所有操作,要么全做,要么全不做。事务在执行过程中如果出现差错会全部回滚到最初的状态

  • 一致性(Correspondence):在事务开始之前以及结束之后,数据库的完整性约束不会被破坏

  • 隔离性(Isolation):隔离状态下执行事务,使他们好像是系统在给定时间内执行的唯一操作

  • 持久性(Durability):在事务完成后,该事务对数据库所做的操作都会全部持久的保存在数据库中,不会被回滚

MySQLMyISAMInnoDB 的区别

  • InnoDB支持事务,而MyISAM不支持事务

  • InnoDB支持行级锁,而MyISAM支持表级锁

  • InnoDB支持MVCC, 而MyISAM不支持

  • InnoDB支持外键,而MyISAM不支持

  • InnoDB不支持全文索引,而MyISAM支持。

  • InnoDB不能通过直接拷贝表文件的方法拷贝表到另外一台机器,MyISAM 支持

  • InnoDB表支持多种行格式,MyISAM不支持

  • InnoDB是索引组织表,MyISAM 是堆表

InnoDB引擎的4大特性

  • 插入缓冲(insert buffer)

  • 二次写(double write)

  • 自适应哈希索引(ahi)

  • 预读(read ahead)

MyISAMInnoDB两者select count(*)哪个更快,为什么

  • MyISAM更快,因为MyISAM内部维护了一个计数器,可以直接调取

InnoDB的事务与日志的存放形式

  • redo:在页修改的时候,先写到 redo log buffer 里面,然后写到 redo log 的文件系统缓存里面(fwrite),然后再同步到磁盘文件(fsync

  • undo:在 MySQL5.5 之前,undo 只能存放在 ibdata* 文件里面,5.6 之后,可以通过设置 innodb_undo_tablespaces 参数把 undo log 存放在 ibdata* 之外

InnoDB的事务是如何通过日志来实现的

  • 事务在修改页时,要先记 undo,在记 undo 之前要记 undoredo,然后修改数据页,再记数据页修改的 redo

  • redo(里面包括 undo 的修改) 一定要比数据页先持久化到磁盘。

  • 当事务需要回滚时,因为有 undo,可以把数据页回滚到前镜像的状态,崩溃恢复时,如果 redo log 中事务没有对应的 commit 记录,那么需要用 undo 把该事务的修改回滚到事务开始之前。

  • 如果有 commit 记录,就用 redo 前滚到该事务完成时并提交掉。

explain 中的索引问题

  • explain 结果中,一般来说,要看到尽量用 index(typeconstref 等,key 列有值),避免使用全表扫描(type 显式为 ALL)。

  • 比如说有 where 条件且选择性不错的列,需要建立索引。

  • 被驱动表的连接列,也需要建立索引。被驱动表的连接列也可能会跟 where 条件列一起建立联合索引。

  • 当有排序或者 group by 的需求时,也可以考虑建立索引来达到直接排序和汇总的需求。

MySQLInnoDB引擎的行锁是通过加在什么上完成(或称实现)的?

  • InnoDB是基于索引来完成行锁

  • 例如,select * from tab_with_index where id = 1 for update;
    for update 可以根据条件来完成行锁锁定,并且 id 是有索引键的列, 如果 id 不是索引键那么InnoDB将加上表锁

描述下 MySQLInnoDB 支持的四种事务隔离级别名称,以及逐级之间的区别?

  • 读未提交(read uncommitted)
    读已提交(read committed)
    可重复读(repeatable read)
    串行(serializable)

  • Read Uncommitted:可以读取其他 session 未提交的脏数据。
    Read Committed:允许不可重复读取,但不允许脏读取。提交后,其他会话可以看到提交的数据。
    Repeatable Read: 禁止不可重复读取和脏读取、以及幻读(innodb 独有)。
    Serializable: 事务只能一个接着一个地执行,但不能并发执行。事务隔离级别最高。
    不同的隔离级别有不同的现象,并有不同的锁定/并发机制,隔离级别越高,数据库的并发性就越差。

Kafka

为什么要使用 kafka,为什么要使用消息队列

  • 缓冲和削峰:上游数据时有突发流量,下游可能扛不住,或者下游没有足够多的机器来保证冗余,kafka 在中间可以起到一个缓冲的作用,把消息暂存在 kafka 中,下游服务就可以按照自己的节奏进行慢慢处理。

  • 解耦和扩展性:项目开始的时候,并不能确定具体需求。消息队列可以作为一个接口层,解耦重要的业务流程。只需要遵守约定,针对数据编程即可获取扩展能力。

  • 冗余:可以采用一对多的方式,一个生产者发布消息,可以被多个订阅topic的服务消费到,供多个毫无关联的业务使用。

  • 健壮性:消息队列可以堆积请求,所以消费端业务即使短时间死掉,也不会影响主要业务的正常进行。

  • 异步通信:很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。

Kafka中的 broker 是干什么的

  • broker 是消息的代理,ProducersBrokers 里面的指定 Topic 中写消息,ConsumersBrokers 里面拉取指定 Topic 的消息,然后进行业务处理,broker 在中间起到一个代理保存消息的中转站。

Kafka中是怎么体现消息顺序性的?

  • kafka每个 partition 中的消息在写入时都是有序的,消费时,每个partition只能被每一个group中的一个消费者消费,保证了消费时也是有序的。整个topic不保证有序。如果为了保证topic整个有序,那么将partition调整为1.

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!


欢迎关注我的公众号😘