Moka-Java后端开发-一面 面经

1. 简单做个自我介绍

参考答案:您好,我叫XXX,目前是XX大学计算机专业研究生/本科在读。我主要学习Java后端开发,熟悉Spring Boot、MyBatis、Redis等技术栈。在项目经验方面,我参与开发过电商系统的订单模块,负责订单创建、支付回调、库存扣减等核心功能,期间使用Redis解决了库存超卖问题,通过分库分表优化了订单查询性能。我还做过一个社交平台项目,实现了用户关注、动态发布、消息推送等功能,使用Kafka处理异步消息,用Elasticsearch实现内容搜索。

我对技术比较感兴趣,平时会阅读技术博客和源码,了解JVM原理、并发编程、分布式系统等知识。我希望能加入Moka这样的SaaS公司,在HR系统这个领域深入学习,提升自己的技术能力和业务理解。

2. 你的项目中用到了哪些设计模式?

参考答案:在电商订单系统中,我用了多种设计模式。单例模式用在配置管理类,保证全局只有一个实例。工厂模式用在支付模块,根据支付类型(微信、支付宝、银联)创建不同的支付处理器。策略模式用在优惠计算,不同的促销活动(满减、折扣、赠品)有不同的计算策略,通过策略接口统一调用。

模板方法模式用在订单处理流程,定义了创建订单的骨架(校验参数、锁库存、创建订单、扣库存、发消息),子类实现具体步骤。观察者模式用在订单状态变更,订单支付成功后通知库存系统、物流系统、积分系统等多个模块。责任链模式用在订单校验,价格校验、库存校验、用户权限校验等形成一条链,依次执行。

这些设计模式让代码更灵活、可扩展,新增支付方式或促销活动时不需要修改原有代码,符合开闭原则。

3. ArrayList和LinkedList的区别,什么场景用哪个?

参考答案:ArrayList底层是数组,LinkedList底层是双向链表。

ArrayList的优势:随机访问快,通过索引访问是O(1)。内存连续,缓存友好,遍历效率高。占用空间小,只存数据和少量扩容空间。

ArrayList的劣势:插入删除慢,中间插入删除需要移动元素,是O(n)。扩容有开销,默认扩容1.5倍,需要复制数组。

LinkedList的优势:插入删除快,只需要修改指针,是O(1)。不需要连续内存,不需要扩容。

LinkedList的劣势:随机访问慢,需要从头或尾遍历,是O(n)。占用空间大,每个节点要存前后指针。缓存不友好,节点分散在内存中。

使用场景:如果主要是查询和遍历,用ArrayList。如果频繁在头尾插入删除,用LinkedList。如果需要随机插入删除,两者都不理想,考虑用其他数据结构。实际开发中ArrayList用得更多,因为大部分场景是查询多于修改。

4. ConcurrentHashMap的实现原理,JDK 1.7和1.8有什么区别?

参考答案:ConcurrentHashMap是线程安全的HashMap,JDK 1.7和1.8实现完全不同。

JDK 1.7用分段锁(Segment)实现。Segment继承ReentrantLock,默认16个Segment,每个Segment管理一部分数据。put操作只锁对应的Segment,不同Segment可以并发操作,并发度是Segment数量。缺点是Segment数量固定,并发度有上限,且结构复杂。

JDK 1.8抛弃了Segment,改用Node数组+链表/红黑树,结构和HashMap一样。用synchronized+CAS实现线程安全。put操作时,如果桶为空,用CAS插入。如果桶不为空,用synchronized锁住桶的头节点,只锁一个桶,并发度更高。链表长度超过8转红黑树,提升查询效率。

JDK 1.8的优势:并发度更高,锁粒度更细,每个桶都可以独立加锁。结构更简单,去掉了Segment层。synchronized经过优化,性能不比ReentrantLock差。红黑树提升了哈希冲突时的性能。

5. 讲讲JVM的内存结构和垃圾回收算法

参考答案:JVM内存分为堆、方法区、虚拟机栈、本地方法栈、程序计数器。堆是最大的区域,存放对象实例,分为年轻代(Eden、Survivor0、Survivor1)和老年代。方法区存类信息、常量、静态变量,JDK 8后改为元空间,使用本地内存。虚拟机栈存局部变量、操作数栈、方法出口等,每个方法对应一个栈帧。

垃圾回收主要针对堆。判断对象是否存活用可达性分析,从GC Roots(栈中引用、静态变量、常量等)出发,能到达的对象是存活的,不能到达的是垃圾。

垃圾回收算法:标记-清除算法,标记垃圾对象然后清除,会产生内存碎片。复制算法,将存活对象复制到另一块内存,清空原内存,没有碎片但浪费空间,用于年轻代。标记-整理算法,标记后将存活对象移到一端,清理边界外的内存,用于老年代。分代收集算法,年轻代用复制算法,老年代用标记-整理算法。

常见垃圾收集器:Serial、ParNew、Parallel Scavenge用于年轻代,CMS、G1可以收集整个堆。G1是目前主流,将堆分为多个Region,可以预测停顿时间。

6. Spring Boot的自动配置原理是什么?

参考答案:Spring Boot的自动配置通过@EnableAutoConfiguration注解实现。这个注解导入了AutoConfigurationImportSelector类,它会扫描所有jar包中的META-INF/spring.factories文件,读取EnableAutoConfiguration对应的配置类列表。

每个自动配置类都有@Conditional注解,根据条件决定是否生效。常见的条件注解:@ConditionalOnClass判断类路径是否存在某个类,@ConditionalOnBean判断容器中是否有某个Bean,@ConditionalOnProperty判断配置文件是否有某个属性。

例如RedisAutoConfiguration,只有当类路径存在RedisOperations类时才生效,会自动创建RedisTemplate等Bean。如果用户自己定义了RedisTemplate,自动配置会失效,因为有@ConditionalOnMissingBean注解。

自动配置的好处:开箱即用,引入starter依赖就能使用功能。约定优于配置,提供默认配置,减少配置工作。灵活可定制,可以通过配置文件或自定义Bean覆盖默认配置。

理解自动配置原理有助于排查问题,比如某个功能不生效,可以检查条件注解是否满足,配置文件是否正确。

7. MySQL的索引失效场景有哪些?

参考答案:索引失效的常见场景:使用函数或表达式,如WHERE YEAR(create_time) = 2024,索引失效,应该用范围查询。类型转换,如字符串字段用数字查询WHERE phone = 12345678901,会隐式转换,索引失效。

模糊查询以%开头,如WHERE name LIKE '%张%',索引失效。如果是WHERE name LIKE '张%',索引有效。or连接的条件,如果or前后有一个字段没索引,整个查询不走索引。应该改用union或者给所有字段加索引。

联合索引不满足最左前缀原则,如索引是(a,b,c),查询WHERE b=1 AND c=2不走索引,必须有a。但WHERE a=1 AND c=2会走索引,只用到a。不等于、not in、not exists通常不走索引,优化器认为扫描范围太大。is null可能走索引,is not null通常不走。

数据量太小,优化器认为全表扫描更快,不走索引。数据分布不均匀,如果查询条件覆盖大部分数据,优化器选择全表扫描。

优化建议:避免在索引列上使用函数和表达式。注意类型匹配,避免隐式转换。合理使用联合索引,注意顺序。用explain分析执行计划,确认是否走索引。

8. 讲讲Spring的AOP实现原理

参考答案:AOP(面向切面编程)用于将横切关注点(日志、事务、权限等)从业务逻辑中分离。Spring AOP基于动态代理实现,有JDK动态代理和CGLIB代理两种方式。

JDK动态代理:目标对象实现了接口,Spring使用JDK动态代理。通过Proxy.newProxyInstance创建代理对象,实现InvocationHandler接口,在invoke方法中织入增强逻辑。优点是JDK自带,不需要额外依赖。缺点是只能代理接口,不能代理类。

CGLIB代理:目标对象没有实现接口,Spring使用CGLIB代理。CGLIB通过字节码技术生成目标类的子类,重写方法织入增强逻辑。优点是可以代理类。缺点是不能代理final类和final方法,需要额外依赖。

AOP的核心概念:切面(Aspect)是切点和通知的组合。切点(Pointcut)定义在哪里织入,用表达式匹配方法。通知(Advice)定义织入什么逻辑,有前置、后置、环绕、异常、最终通知。

Spring AOP是运行时增强,在Bean初始化时创建代理对象。AspectJ是编译时增强,功能更强大但需要特殊编译器。Spring AOP满足大部分场景,性能开销

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Java面试圣经 文章被收录于专栏

Java面试圣经,带你练透java圣经

全部评论

相关推荐

评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务