数据库
淘宝 Java ⾯试
阿⾥巴巴 的淘天集团校招薪资也开了,也就是做淘宝业务的集团,上来跟⼤家汇报汇报。
25 届淘天集团的后端开发的校招薪资情况:

ssp offer :29k x 16 + 4w 签字费,同学 bg 硕⼠ 211 ,base 杭州
sp offer :26k x 16 + 1w 签字费,同学 bg 未知,base 杭州
普通 offer :24k x 16 + 1w 签字费,同学 bg 硕⼠985 ,base 杭州
除此之外,还有⼀些补贴福利,房补 2k/ ⽉(共两年),交通费 800 元/⽉,搬家费 6k (⼀次性),杭州市⼈才补贴等等 。
整体上,跟蚂蚁 集团 25 届薪资 差不多,⼤概率阿⾥巴巴 其他集团的校招开奖薪资也是类似。
今天给⼤家分享阿⾥巴巴 Java 校招⾯经,同学的⾯试感受是「吹爆阿⾥,整个⾯试过程体验很不
错,⾯试官⼀直引导」。
可惜同学没把握住,后⾯还是挂了。
考察内容还是⽐较多,我帮⼤家罗列了⼀下:
数据库:SQL 与 NOSQL ,数据库场景
Redis :持久化
MySQL :存储引擎、事务、锁
操作系统:进程线程、linux 命令
Java :线程、线程池、容器、⾯向对象特性
⽹络:⽹络通信协议

数据库
数据库怎么分类,描述⼀下你对这些数据库的理解?
按照数据模型来分类的话,主要分为关系型数据库和⾮关系型数据库
关系型数据库:基于关系模型组织 数据的数据库,如MySQL 、Oracle 等。
⾮关系型数据库:不使⽤传统表格形式 存储数据的数据库,如MongoDB 、Redis 等。
我的理解是,数据库是⽤于存储、管理和检索数据的系统,关系型数据库使⽤结构化查询语⾔
(SQL )来管理数据,适⽤于需要保证数据⼀致性和完整性的场景;NoSQL 数据库则更加灵活,适
⽤于需要处理⼤量⾮结构化数据或需要⾼可伸缩性的场景。
什么 情况使⽤MySQL ,什么 情况使⽤Redis ?
当需要存储结构化数据,并且需要⽀持复杂的查询操作时,和需要⽀持事务处理时,可以选择
MySQL 。
当需要快速访问和处理数据的缓存时,可以选择Redis ,能够提供快速的数据读取和写⼊。
⼀般Redis 会作 为MySQL 的缓存,提⾼服务器系统的查询性能。假如⽤⼾第⼀次访问 MySQL 中的
某些数据。这个过程会⽐较慢,因为是从硬盘上读取的。将该⽤⼾访问的数据缓存在 Redis 中,这
样下⼀次再访问这些数据的时候就可以直接从缓存中获取了,操作 Redis 缓存就是直接操作内存,
所以速度相当快 。

Redis
Redis 有什么 持久化策略?
Redis 的读写操作都是在内存中,所以 Redis 性能才会⾼,但是当 Redis 重启后 ,内存中的数据就
会丢失,那为了 保证内存中的数据不会丢失,Redis 实现了数据持 久化的机制,这个机制会把数据
存储到磁盘,这样在 Redis 重启就能够从磁盘中恢复原有的数据。
Redis 共有三种数据持 久化的⽅式:
AOF ⽇志:每执⾏⼀条写操作命令,就把该命令以 追加的⽅式写⼊到⼀个⽂件⾥;
RDB 快照:将某⼀时刻的内存数据,以⼆进制的⽅式写⼊磁盘;
混合持久化⽅式:Redis 4.0 新增的⽅式,集成了 AOF 和 RDB 的优点;
MySQL
MySQL 有哪2种引擎,说⼀下它们的区别?
MySQL 中常⽤的存储引擎分别 是:MyISAM 存储引擎、innoDB 存储引擎,他们的区别在于:
事务:InnoDB ⽀持事务,MyISAM 不⽀持事务,这是 MySQL 将默认存储引擎从 MyISAM 变成
InnoDB 的重要原因之⼀。
索引结构:InnoDB 是聚簇索引,MyISAM 是⾮聚簇索引。聚簇索引的⽂件存放在主键索引的叶
⼦节点上,因此 InnoDB 必须要有主键,通过主键索引效率很⾼。但是辅助索引需要两次查
询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过⼤,因为主 键太⼤,其
他索引也都会很⼤。⽽ MyISAM 是⾮聚簇索引,数据⽂件是分离的,索引保存的是数据⽂件的
指针。主键索引和辅助索引是独⽴的。
锁粒度:InnoDB 最⼩的锁粒度是⾏锁,MyISAM 最⼩的锁粒度是表锁。⼀个更新语句会锁住整
张表,导致其他查询和更新都会被阻塞,因此并发访问受限。
count 的效率:InnoDB 不保存表的具体⾏数,执⾏ select count(*) from table 时需要全表扫描。⽽MyISAM ⽤⼀个变量保存了整个表的⾏数,执⾏上述语句时只需要读出该变量即可,速
度很快 。
MySQL 两个 线程的update 语句同时处理⼀条数据,会不会有阻塞?
如果是两个事 务同时更新了 id = 1 ,⽐如 update ... where id = 1 ,那么是会阻塞的。因为 InnoDB存储引擎实现了⾏级锁。
当A事务对 id =1 这⾏记录进⾏更新时,会对主键 id 为 1 的记录加X类型的记录锁,这样第⼆事务
对 id = 1 进⾏更新时,发现已经有记录锁了,就会陷⼊阻塞状态。滥⽤事务,或者⼀个事 务⾥有特别多sql 的弊端?
事务的资源在事务提交之 后才会释放的,⽐如存储资源、锁。
如果⼀个事 务特别多 sql ,那么会带来这些问题:
如果⼀个事 务特别多 sql ,锁定的数据太多 ,容易造成⼤量的死锁和锁超时。
回滚记录会占⽤⼤量存储空间,事务回滚时间⻓。在MySQL 中,实际上每条记录在更新的时候
都会同时记录⼀条回滚操作。记录上的最新值,通过回滚操作,都可以得到前 ⼀个状态的值,
sql 越多,所需要保存的回滚数据就越多。
执⾏时间⻓,容易造成主从 延迟,主库上必须等事务执⾏完成才 会写⼊binlog ,再传给备库。
所以,如果⼀个主 库上的语句执⾏10 分钟,那这个事 务很可能就会导致从库延迟10 分钟
两条update 语句处理⼀张表的不同的主键范围的记录,⼀个<10 ,⼀个
>15 ,会不会遇到阻塞?底层是为什么 的?
不会,因为锁住的范围不⼀样,不会形成冲突。
第⼀条 update sql 的话( id<10 ),锁住的范围是(-♾,10 )
第⼆条 update sql 的话(id >15 ),锁住的范围是(15 ,+♾)如果2个范围不是主键或索引?还会阻塞吗?
如果2范围查询的字段不是索引的话,那就代表 update 没有⽤到索引,这时候触发了全表扫描,
全部索引都会加⾏级锁,这时候第⼆条 update 执⾏的时候,就会阻塞了。
因为如果 update 没有⽤到索引,在扫描过程中会对索引加锁,所以全表扫描的场景下,所有记录
都会被加锁,也就是这条 update 语句产⽣了 4 个记录锁和 5 个间隙 锁,相当于锁住了全表。

除了表锁,⾏锁这些,还有别的形式 的锁吗?
还有全局锁。全局锁:通过flush tables with read lock 语句会将整个数据库就处于只读状态了,这
时其他线程执⾏以下操作,增删改或者表结构修改都会阻塞。全局锁主要应⽤于做全库逻辑备
份,这样在备份数据库期间,不会因为数据或表结构的更新,⽽出现备份⽂件的数据与预期的不
⼀样。
操作系统
谈⼀下对线程和进程的理解

本质区别:进程是操作系统资源分配的基本单位,⽽线程是任务调度和执⾏的基本单位
在开销⽅⾯:每个进程都有独⽴的代码和数据空间(程序上下 ⽂),程序之间的切换会有较⼤的
开销;线程可以看做轻量级的进程,同⼀类线程共享代码和数据空间,每个线程都有⾃⼰独⽴
的运⾏栈和程序计数器( PC ),线程之间切换的开销⼩
稳定性⽅⾯:进程中某个线程如果崩溃了,可能会导致整个进程都崩溃。⽽进程中的⼦进程崩
溃,并不会影响其他进程。
内存分配⽅⾯:系统在运⾏的时候会为每个进程分配不同的内存空间;⽽对线程⽽⾔,除了
CPU 外,系统不会为线程分配内存(线程所使⽤的资源来⾃其所属进程的资源),线程组之间只
能共享资源
包含关系:没有线程的进程可以看做是单线程的,如果⼀个进程内有多个线程,则执⾏过程不
是⼀条线的,⽽是多条线(线程)共同完成的;线程是进程的⼀部分,所以线程也被称为轻权
进程或者轻量级进程
多线程⽐单线程的优势,劣势
多线程⽐单线程的优势:提⾼程序的运⾏效率,可以充分利 ⽤多核处理器的资源,同时处理多
个任务,加快程序的执⾏速度。
多线程⽐单线程的劣势 :存在多线程数据竞争访问的问题,需要通过锁机制来保证线程安全,
增加了加锁的开销,并且还会有死锁的⻛险。多线程会消耗更多系统资源,如CPU 和内存,因
为每个线程都需要占⽤⼀定的内存和处理时间。
Linux 操作系统中哪个命令可以查看端⼝被哪个应⽤占⽤?使⽤ lsof 命
令:
可以使 ⽤ lsof 命令或 netstat 命令查看端⼝被哪个应⽤占⽤。
使⽤ netstat 命令:
netstat -tulnp | grep 端口号
这两个 命令都可以帮助你找到哪个应⽤程序占⽤了特定的端⼝。
Java
Java 创建线程有⼏种⽅式
⽅式⼀:继承Thread 类并重写run() ⽅法。
public class CreatingThread01 extends Thread {
@Override
public void run() {
System.out.println(getName() + " is running");
}
public static void main(String[] args) {
new CreatingThread01().start();
new CreatingThread01().start();
new CreatingThread01().start();
new CreatingThread01().start();
}
}采⽤继承Thread 类⽅式
优点: 编写简单,如果需要访问当前线程,⽆需使⽤Thread.currentThread () ⽅法,直接使⽤this ,即可获得当 前线程
缺点:因为线程类已经继 承了Thread 类,所以不能再继承其他的⽗类
⽅式⼆:实现Runnable 接⼝并实现run() ⽅法,然后将实现了Runnable 接⼝的类传递给Thread 类。
public class CreatingThread02 implements Runnable {
@Override
public void run() {
public static void main(String[] args) {
new Thread(new CreatingThread02()).start();
new Thread(new CreatingThread02()).start();
new Thread(new CreatingThread02()).start();
new Thread(new CreatingThread02()).start();
}
}采⽤实现Runnable 接⼝⽅式:
优点:线程类只是实现了Runable 接⼝,还可以继承其他的类。在这种⽅式下,可以多个线程共
享同⼀个⽬标对象,所以⾮常适合多个相同线程来处理同⼀份资源的情况,从⽽可以将CPU 代
码和数据分开,形成清晰的模型,较好地体现了⾯向对象的思想。
缺点:编程稍 微复杂,如果需要访问当前线程,必须使⽤Thread.currentThread() ⽅法。⽅式三:使⽤Callable 和Future 接⼝通过Executor 框架创建线程。
public class CreatingThread03 implements Callable<Long> {
@Override
public Long call() throws Exception {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getId() + " is running");
return Thread.currentThread().getId();
}
public static void main(String[] args) throws ExecutionException, InterruptedExceptio
FutureTask<Long> task = new FutureTask<>(new CreatingThread03());
new Thread(task).start();
System.out.println("等待完成任务");
Long result = task.get();
System.out.println("任务结果:" + result);
}
}采⽤实现Callable 接⼝⽅式:
缺点:编程稍 微复杂,如果需要访问当前线程,必须调⽤Thread.currentThread() ⽅法。优点:线程只是实现Runnable 或实现Callable 接⼝,还可以继承其他类。这种⽅式下,多个线程
可以共享⼀个target 对象,⾮常适合多线程处理同⼀份资源的情形。
线程池有哪些优势?
减少线程创建和销毁的开销:频繁地创建和销毁线程会消耗⼤量系统资源,线程池通过重⽤已
存在的线程来减少这种开销。
提⾼响应速度:当任务到 达时,⽆需等待线程的创建即可⽴即执⾏,因为线程池中已经有等待
的线程。
说⼀下⾯向对象3⼤特性理解?
Java ⾯向对象的三⼤特性包括:封装、继承、多态:
封装:封装是指将对 象的属性(数据)和⾏为(⽅法)结合在⼀起,对外隐藏对象的内部细
节,仅通过对象提供的接⼝与外界交互 。封装的⽬的是增强安全性和简化编程,使得对象更加
独⽴。
继承:继承是⼀种可以使 得⼦类⾃动共享⽗类数据结构和⽅法的机制。它是代码复⽤的重要⼿
段,通过继承可以建⽴类与类之间的层次关系,使得结构更 加清晰。
多态:多态是指允许不同类的对象对同⼀消息作出响应。即同⼀个接⼝,使⽤不同的实例⽽执
⾏不同操作。多态性 可以分为编译时多态(重载)和运⾏时多态(重写)。它使得程序具有良好
的灵活性和扩展性。
Java 有什么 常⽤的集合类?
Java 中常⽤的集合类主要分为四个类别:List 、Set 、Map 、Queue 。

List (列表):是⼀个有序的集合,可以包含重复的元素。主要实现类有 ArrayList 、
LinkedList 和 Vector 。 ArrayList 是基于动态数组实现,适合随机访问元素; LinkedList
基于双向链表实现,适合插⼊、删除操作频繁的场景。
Set (集合):是⼀个不 允许有重复元素的集合。主要实现类有 HashSet 、 LinkedHashSet 和
TreeSet 。 HashSet 基于哈希表实现,最常⽤; LinkedHashSet 继承⾃ HashSet ,但是可以
维护元素插⼊的顺序; TreeSet 基于红⿊树实现,元素会按照某种⽐较规则进⾏排序。
Map (映射):是⼀种键值对的集合,提供键到值的映射。主要实现类有 HashMap 、
LinkedHashMap 和 TreeMap 。 HashMap 是基于哈希表实现,存取⾼效; LinkedHashMap 基于
HashMap 实现,但可以保 持插 ⼊顺序; TreeMap 基于红⿊树实现,按照键的⾃然顺序或者构造
时提供的 Comparator 进⾏排序。
Queue (队列):是⼀种先进先出(FIFO )的数据结构。常⽤实现类有 LinkedList (也实现了
Deque 接⼝), PriorityQueue 等。 PriorityQueue 是基于优先级堆实现的⽆界优先级队列,
元素按照⾃然顺序或者构造时提供的 Comparator 决定的顺序被访问。
有哪些集合类是线程安全的,哪些是不安全的?
Vector 、HashTable 、Properties 是线程安全的;
ArrayList 、LinkedList 、HashSet 、TreeSet 、HashMap 、TreeMap 等都是线程不安全的。
数组和链表有什么 区别?
访问效率:数组可以通过索引直接访问任何位 置的元素,访问效率⾼,时间复杂度为O(1) ,⽽
链表需要从头节点开始遍历到⽬标位置,访问效率较低,时间复杂度为O(n) 。
插⼊和删除操作效率:数组插⼊和删除操作可能需要移动其他元素,时间复杂度为O(n) ,⽽链
表只需要修改指针指向,时间复杂度为O(1) 。** 缓存命中率:** 由于数组元素在内存中连续存储,可以提⾼CPU 缓存的命中率,⽽链表节点不
连续存储,可能导致CPU 缓存的命中率较低,频繁的缓存失效会影响性能。
应⽤场景:数组适合静态⼤⼩、频繁访问元素的场景,⽽链表适合动态⼤⼩、频繁插⼊、删除
操作的场景
堆和栈的区别?
分配⽅式:堆是动态分配内存,由程序员⼿动申请和释放内存,通常⽤于存储动态数据结构和
对象。栈是静态分配内存,由编译器⾃动分 配和释放内存,⽤于存储函数的局部变量和函数调
⽤信息。
内存管理:堆需要程序员⼿动管理内存的分配和释放,如果管理不当可能会导致内存泄漏或内
存溢出。栈由编译器⾃动管理内存,遵循后进先出的原则,变量的⽣命周 期由其作⽤域决定,
函数调⽤时分配内存,函数返回时释放内存。
⼤⼩和速度:堆通常⽐栈⼤,内存空间较⼤,动态分配和释放内存需要时间开销。栈⼤⼩有
限,通常⽐较⼩,内存分配和释放速度较快,因为是编译器⾃动管理。
Set 集合有什么 特点?如何实现key ⽆重复的?
set 集合特点:Set 集合中的元素是唯⼀的,不会出现重复的元素。
set 实现原理:Set 集合通过内部的数据结构(如哈希表、红⿊树等)来实现key 的⽆重复。当向
Set 集合中插⼊元素时,会先根据元素的hashCode 值来确定元素的存储位置,然后再通过equals
⽅法来判断是否已经存在相同的元素,如果存在则不会再次插⼊,保证了元素的唯⼀性。
有序的Set 是什么 ?记录插⼊顺序的集合是什么 ?
有序的 Set 是TreeSet 和LinkedHashSet 。TreeSet 是基于红⿊树实现,保证元素的⾃然顺序。
LinkedHashSet 是基于双重链表和哈 希表的结合来实现元素的有序存储,保证元素添加的⾃然顺
序记录插⼊顺序的集合通常指的是LinkedHashSet ,它不仅 保证元素的唯⼀性,还可以保 持元素的
插⼊顺序。当需要在Set 集合中记录元素的插⼊顺序时,可以选择使⽤LinkedHashSet 来实现。
⽹络
⽹络有什么 常⽤的通信协议?
HTTP :⽤于在Web 浏览器和Web 服务器之间传输超⽂本的协议,是⽬前最常⻅的应⽤层协议。
HTTPS :在HTTP 的基础上添加了SSL/TLS 加密层,⽤于在不安全的⽹络上安全地传输数据。
TCP :⾯向连接的传输层协议,提供可靠的数据传输服务,保证数据的顺序和完整性。
UDP :⽆连接的传输层协议,提供了数据包传输的简单服务,适⽤于实时性要求⾼的应⽤。
IP :⽹络层协议,⽤于在⽹络中传输数据包,定义了 数据包的格式和传输规则。
前后端交互 ⽤的是什么 协议?
⽤HTTP 和HTTPS 协议⽐较多。
前端通过HTTP 协议向服务器端发送请求,服务器端接收请求并返回相应的数据,实现了前后端的
交互 。HTTP 协议简单、灵活,适⽤于各种类型的应⽤场景。
算法
算法:快乐数,每⼀位平⽅求和,循环操作是否可 以变为1
