我来自一所名气不大的双非一本院校,学习计算机科学与技术。大二时,由于家庭的一些影响和对未来的迷茫,我选择了考研这条路。
去年,因为备战考研而错过了秋季招聘,走出考场的那一刻,我意识到自己在研究生之路上已无法继续。经过一年半的刻苦准备,最终因某校复试线上涨45分而无奈落败。我感到失落和痛苦,但我明白,沉溺于失落并不能为我带来美好的未来,也无法实现我早已规划的梦想。因此,我毅然加入了成千上万的春招大军,尽管我并不知道未来等待我的是什么。
起初,我的专业课程中只涉及了两门Java相关的内容,而且因为当时不够重视,导致我对Java的理解仅停留在面向对象的基础知识上,能做的只是一些简单的条件判断和循环控制。
在准备过程中,我通过各种招聘网站和前辈的建议,逐渐了解到封装、继承、多态,以及企业开发中使用的框架、分布式和微服务等相关知识。看着那些学习路线图,我感到害怕,但时间却不允许我继续犹豫,咬紧牙关,开始了我的学习旅程!
备战面试
以下是我从开始学习到现在的时间表。
- 一月中上旬,我开始根据马士兵的Java SE视频学习。我知道基础知识的重要性,因此在每天听完几个小节后,**我会在晚上复盘当天学习的知识,并将其记录在博客上,同时在第二天找时间进行复习。**这样的学习方式持续到二月中旬。
 - 二月中旬到二月底,我开始学习前端(HTML、CSS、JavaScript、Vue、ElementUI)。这一阶段我仅仅掌握了一些基础语法,完成了几个Demo和两个项目作业,这是为了后续项目的铺垫。由于学习相对简单,我也经常复习SE的相关知识。
 - 三月初,我开始关注牛客网、Boss直聘和携程的招聘信息,同时学习Java EE知识并不断迭代自己的项目。从最基本的SSM到后来的SpringBoot,我意识到亲自动手实现想法才是最佳学习方法。
 - 到三月二十号,我基本完成了项目的核心功能,虽然还有一些功能停留在想法阶段,考虑到时间的关系,我没有继续完善。从这个时间段起直到五月中旬,我参与了多场笔试和面试,准备了面试中的常见问题。
 
我的面经
以下是我在字节飞书、哈啰、谷歌中国、美团及其他中小企业面试中被问到的一些知识点,供大家参考。
Java基础知识
- JDK、JVM与JRE的区别
 - 包装类型的常量池技术
 - 接口与抽象类的区别
 - String、StringBuffer、StringBuilder的区别
 - 泛型擦除的原理
 - 反射的应用场景
 - 异常类型及示例
 - 常用容器及其特点
 - ArrayList的扩容机制
 - HashMap源代码实现
 - ConcurrentHashMap的底层实现
 - Lambda表达式的优缺点及应用场景
 
Java并发
- 多线程的优势及具体场景
 - 线程生命周期及其状态标志
 - 避免死锁的三个必要条件
 - 简述哲学家就餐问题与银行家算法
 - 为什么调用start()时执行run(),而不能直接调用run()?
 - 场景题:如何实现实时排序的游戏战力榜单?
 - 场景题:如何实现高并发的竞技场挑战功能?
 - volatile的用法
 - synchronized与ReentrantLock的区别
 - 乐观锁与悲观锁的底层实现
 - 如何在不加锁的情况下保证线程安全?
 - synchronized是可重入锁吗?
 - 使用vector就一定能保证线程安全吗?
 - 多线程实现方式
 - 场景题:如何在高并发情况下保证数据一致性?
 - 场景题:10个线程对i=0做10次自增,最后i的值是多少,为什么?
 - ThreadLocal的原理
 - 场景题:在生产者消费者问题中如何保证当消费者用完产品后,生产者能及时得知?
 - Java线程池类型及参数含义
 - 线程池的拒绝策略
 
JVM相关知识
- JVM的基本结构
 - 双亲委派模型的优点
 - 运行时数据区的基本结构及用途
 - 垃圾回收策略
 - 垃圾回收器种类
 - 如何判断一个类是否无用
 - 查看JVM状态的方法
 - G1回收器与旧版的不同
 - 类加载过程及其每个阶段的功能
 - JVM常用参数及调优手段
 
Spring框架
- Spring的特性与优势
 - Spring的组件种类
 - 场景题:如何实现一个简单的Spring框架?
 - Spring MVC的底层实现原理
 - IOC与AOP的具体介绍
 - Spring Bean是什么?
 - IOC与DI的关系
 - IOC配置的三种方式
 - 依赖注入的三种方式及构造器注入的优势
 - 场景题:构造器注入类过多时的解决方案
 - AspectJ注解特性及不足
 - Spring如何处理非单例属性的循环依赖?
 - Spring中Bean的生命周期
 - 场景题:自定义一个starter的实现方式
 
MyBatis知识点
- 接口层与数据库交互的方式
 - MyBatis的层次结构
 - sqlSessionFactory与SqlSession的介绍
 - Excutor的概念
 - 动态SQL的种类及用途
 - 连接池的必要性
 - $与#之间的区别
 
计算机网络
- OSI与TCP/IP模型
 - HTTP与HTTPS的区别
 - HTTPS的加密方式
 - TCP三次握手的过程及作用
 - 四次挥手的过程及作用
 - TCP流量控制的作用
 - ARQ协议介绍
 - 从输入URL到页面加载的过程
 - HTTP如何管理用户状态
 - Cookie的作用及与Session的区别
 - HTTP状态码种类
 
数据库知识
- 数据库设计的步骤
 - MySQL的分页方法
 - MyISAM与InnoDB的区别
 - MySQL日志种类及作用
 - 读锁与写锁的底层实现
 - 表级锁与行级锁的实现原理
 - 事务特性
 - 并发事务的常见问题
 - 事务隔离级别的种类
 - 场景题:MySQL应对千万级数据库的策略
 - MVCC的作用
 - 索引的功能及其底层数据结构
 - 为什么InnoDB使用B+树作为索引结构
 - 索引的种类
 - 如何避免回表查询
 - 最左前缀法则
 - 覆盖索引的定义
 - MySQL读写分离方案
 - MySQL主从复制的概念及延迟问题解决方案
 
Redis知识
- Redis为何是单线程的
 - Redis的使用场景
 - Redis支持的数据类型及其应用
 - SDS的存在意义
 - Redis Stream的设计初衷
 - Redis Stream中的消费者崩溃及消息丢失问题
 - Redis Stream中的坏消息与死信问题
 - Redis的持久化机制
 - AOF是写前日志还是写后日志?
 - Redis过期键的删除策略
 - Redis内存淘汰算法
 - Redis如何优化内存使用
 - Redis事务命令及错误处理
 - Redis为何不支持回滚
 - Redis缓存问题及解决方案
 - Redis 6.0之前为何不支持多线程