某游戏大厂Java面试指南:Spring、集合与语言特性深度解析 (三)

137 阅读5分钟

在游戏大厂的Java后端面试中,除了多线程与JVM调优外,Spring框架、集合机制、语言特性也是必考内容。本文将结合真实面试题,深入讲解这些核心知识点。​编辑


一、Spring Bean 的生命周期​编辑

Spring Bean 的生命周期大致分为 七个阶段

  1. 实例化(Instantiation)  
    通过反射创建Bean实例。
  2. 属性赋值(Populate Properties)  
    Spring将配置文件或注解中的属性注入到Bean中。
  3. 实现 BeanNameAware 接口(可选)  
    获取Bean的名称。
  4. 实现 BeanFactoryAware / ApplicationContextAware 接口(可选)  
    获取容器引用。
  5. 初始化前(BeanPostProcessor 前置处理)  
    调用自定义的前置处理逻辑。
  6. 初始化(InitializingBean.afterPropertiesSet() 或 @PostConstruct)  
    完成自定义初始化逻辑。
  7. 销毁(DisposableBean.destroy() 或 @PreDestroy)  
    容器关闭时销毁Bean。

👉 一句话总结:  
Spring Bean 从“创建 → 依赖注入 → 初始化 → 使用 → 销毁”经历完整生命周期,由容器全程管理。


二、Spring 单例 Bean 是否线程安全?​编辑

不一定线程安全。

Spring 的单例 Bean 默认是 全局唯一的实例,如果该 Bean 内部存在可变状态(如成员变量),多个线程同时访问可能会导致 并发问题

  • 无状态 Bean(如 DAO、Service 层的逻辑类) → 线程安全  
  • 有状态 Bean(内部保存用户会话、缓存等数据) → 非线程安全

解决方式:

  1. 使用 ThreadLocal 存储线程独立变量。  
  2. 将 Bean 设计为 无状态。  
  3. 对关键代码块加锁(不推荐,会影响性能)。

三、有状态 Bean 和无状态 Bean 的区别​编辑

类型特征是否线程安全示例
有状态 Bean保存用户或请求相关数据保存Session信息的Bean
无状态 Bean不保存状态,仅执行逻辑Service、DAO类​编辑

四、Spring 事务机制​编辑

Spring 的事务管理基于 AOP(面向切面编程) 实现,通过动态代理在方法执行前后添加事务逻辑。

常见的事务传播行为:

  • REQUIRED(默认):有事务则加入,没有则创建新事务  
  • REQUIRES_NEW:总是新建事务  
  • NESTED:嵌套事务  
  • SUPPORTS:如果存在事务就加入,否则不使用事务  

事务隔离级别(防止脏读、不可重复读、幻读):

  • READ_UNCOMMITTED  
  • READ_COMMITTED  
  • REPEATABLE_READ  
  • SERIALIZABLE  

常用注解:

@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)  

五、如何实现 HashMap 取出顺序与放入顺序一致?

使用 LinkedHashMap。  

LinkedHashMap 继承自 HashMap,但通过 双向链表 维护插入顺序或访问顺序:

Map<String, String> map = new LinkedHashMap<>();  
map.put("A", "1");  
map.put("B", "2");  
map.put("C", "3");  
System.out.println(map.keySet()); // [A, B, C]  

六、HashMap 的扩容时间复杂度及优化

  • 扩容机制:当元素数量超过容量 × 负载因子(默认0.75)时,进行 rehash
  • 时间复杂度:O(n)(每次扩容需要重新计算哈希并移动元素)

优化策略:

  1. 预估容量,在初始化时设置合适的容量:  
    java    new HashMap<>(expectedSize * 2);    
  2. 使用ConcurrentHashMap 避免多线程频繁扩容。  
  3. 避免过多小容量Map,可重用实例。  

七、JDK8 添加的主要特性

  1. Lambda 表达式(函数式编程)  
    java    list.forEach(item -> System.out.println(item));    
  2. Stream API(集合流式操作)  
    java    list.stream().filter(x -> x > 10).forEach(System.out::println);    
  3. 接口默认方法(default method)
  4. Optional 类(避免NullPointerException)
  5. 新的日期时间API(java.time)
  6. Nashorn JavaScript 引擎
  7. ConcurrentHashMap 改进
  8. 类型推断增强

八、Java 为什么既是解释型语言,又是编译型语言?

  • Java 源代码(.java)首先被 编译器编译为字节码(.class) —— 这是编译型语言特征。  
  • 然后由 JVM解释执行,将字节码翻译为机器指令 —— 这是解释型语言特征。  
  • JIT(Just-In-Time)即时编译器结合了两者的优点,使性能接近本地代码。

👉 一句话总结:  
Java 是“先编译再解释”的混合型语言。


九、面向对象与面向过程的区别

对比项面向过程面向对象
核心思想以过程为中心,按步骤解决问题以对象为中心,封装数据与行为
代码复用函数复用继承与多态复用
适用场景简单逻辑、算法密集型复杂系统、模块化开发
示例C语言Java、C++

十、Java 的类与 C++ 的类区别

对比项JavaC++
内存管理自动垃圾回收(GC)手动释放内存
多继承不支持类多继承(通过接口实现)支持类多继承
指针无显式指针可直接操作指针
平台相关性跨平台平台相关
封装性严格访问控制符相对灵活

十一、Java 语言的三大特性

  1. 封装(Encapsulation)  
    - 隐藏内部实现,仅暴露接口。  
    - 提高代码安全性与复用性。  
    java    private int health;    public void setHealth(int h) { this.health = h; }    

  2. 继承(Inheritance)  
    - 子类继承父类属性与方法,增强可扩展性。
    java    class Hero extends Character {}    

  3. 多态(Polymorphism)  
    - 同一方法,不同对象有不同实现。
    java    Character c = new Mage();    c.attack(); // 动态绑定    


✨总结

这份面试指南涵盖了游戏大厂常问的Spring、集合与Java语言特性。  
面试中,除了死记答案,更重要的是结合实际项目去理解“为什么这么设计”——这正是优秀工程师与普通开发者的分界线。