当前位置: 首页 > news >正文

Android第四次面试总结之Java基础篇(补充)

一、设计原则高频面试题(附大厂真题解析)

1. 单一职责原则(SRP)在 Android 开发中的应用(字节跳动真题)
  • 真题:“你在项目中如何体现单一职责原则?举例说明。”
  • 考点:结合实际场景说明职责拆分,避免贫血模型。
  • 满分答案
    在开发网络模块时,原代码将 “网络请求逻辑”“数据解析”“错误处理” 耦合在一个NetworkManager类中,违反 SRP。
    重构方案
    1. 拆分为OkHttpHelper(负责底层网络请求)、DataParser(解析 JSON/Proto 数据)、ErrorHandler(统一处理网络异常);
    2. 高层模块(如UserRepository)依赖这三个抽象组件,通过构造器注入协作。
      优势:每个类仅一个修改原因(如网络库升级只需改OkHttpHelper),降低维护成本。
2. 里氏替换原则(LSP)的经典反例及修正(腾讯真题)
  • 真题:“为什么 Square 不能直接继承 Rectangle?如何正确设计?”
  • 考点:理解继承的约束条件,区分 “Is-a” 与 “Can-do”。
  • 满分答案
    反例分析
    • Rectangle定义setWidth(int w)setHeight(int h),允许宽高独立变化;
    • Square重写这两个方法时,强制宽高相等,破坏父类 “宽高可独立设置” 的契约,违反 LSP(子类不能替换父类)。
      修正方案
    1. 放弃继承,让SquareRectangle实现共同接口Quadrilateral,提供getWidth()getHeight(),但不强制宽高可独立设置;
    2. 或引入MutableRectangle接口,明确 “可修改宽高” 的能力,Square不实现该接口。
3. 依赖倒置原则(DIP)在 MVP 中的应用(阿里真题)
  • 真题:“MVP 架构如何体现依赖倒置原则?”
  • 考点:区分高层模块与低层模块,抽象接口解耦。
  • 满分答案
    MVP 分层
    • 高层模块(Presenter):依赖抽象接口View(如UserView)和Repository(如UserRepository),而非具体实现(ActivityRetrofitImpl);
    • 低层模块(Model/View 实现):实现这些抽象接口,如UserActivity implements UserViewUserRetrofit implements UserRepository
      依赖关系
      Presenter 与具体 Activity / 网络库解耦,可通过依赖注入(如 Dagger)切换实现(如单元测试时用 MockView),符合 “高层模块依赖抽象” 的 DIP 原则。

二、DCL 单例模式大厂真题解析

1. 为什么 DCL 单例需要 volatile?(美团真题)
  • 考点:理解指令重排对单例的影响,volatile 的内存语义。
  • 满分答案
    指令重排风险
    instance = new DCLSingleton()可分解为:
    1. 分配内存空间(memory = allocate());
    2. 初始化对象(ctorInstance(memory));
    3. 将内存地址赋给instanceinstance = memory)。
      JVM 可能重排为 1→3→2,若线程 A 执行到 3 时(instance非空但未初始化),线程 B 调用getInstance()返回未初始化的对象,导致 NPE。
      volatile 作用
    • 禁止指令重排,确保 1→2→3 的顺序;
    • 保证可见性,线程 A 修改instance后,线程 B 立即看到最新值。
      JDK 版本关键:JDK 1.5 + 修复了 volatile 的语义,此前版本 DCL 可能失效,因此现代 Java 必须使用 volatile。
2. 单例模式的线程安全实现有哪些?对比优缺点(百度真题)
  • 考点:掌握不同单例实现的适用场景,反序列化安全。
  • 满分答案
实现方式线程安全优点缺点大厂应用场景
DCL延迟初始化,性能高需 volatile,实现较复杂高并发且内存敏感场景
静态内部类简洁,利用类加载机制安全类加载后立即初始化通用场景(推荐)
枚举单例反序列化安全,防止反射攻击不支持延迟初始化需严格防止实例化场景
  • 反序列化安全
    枚举单例天然支持(Java 规范保证反序列化返回枚举常量),其他方式需重写readResolve()返回单例实例:
    protected Object readResolve() { return instance; }  
    

三、HashMap 高频面试题(附大厂真题解析)

1. JDK8 HashMap 为什么引入红黑树?链表转红黑树的条件?(字节跳动真题)
  • 考点:理解哈希冲突优化,阈值设计原理。

  • 满分答案
    引入红黑树原因
    JDK7 及以前用链表处理哈希冲突,当链表长度为 n 时,查找时间复杂度 O (n)。数据倾斜时(如大量键哈希值相同),链表可能很长,性能下降。
    红黑树将查找、插入、删除的时间复杂度降至 O (logn),提升极端场景下的性能。

    转换条件(两个同时满足)

    1. 链表长度≥8(TREEIFY_THRESHOLD=8);
    2. 数组容量≥64(MIN_TREEIFY_CAPACITY=64)。
      原因
    • 链表长度 8 的概率极低(泊松分布计算,概率仅 0.0000006),若出现则认为是哈希冲突严重;
    • 若数组容量小(如 16),直接扩容比转红黑树更高效(减少树节点维护开销)。
2. 自定义类作为 HashMap 的 Key 需要注意什么?(阿里真题)
  • 考点:正确重写 hashCode 和 equals,不可变性。
  • 满分答案
    1. 必须重写hashCode()equals()
      • 若只重写equals,不同对象可能哈希值相同,导致存入 HashMap 后无法正确查找;
      • 示例:
        class Person {  String id;  @Override public boolean equals(Object o) { ... }  // 必须同时重写hashCode,保证相等对象哈希值相同  @Override public int hashCode() { return Objects.hash(id); }  
        }  
        
    2. Key 建议为不可变类
      • 若 Key 可变,修改后哈希值变化,导致存入的键值对无法通过新值查找(如String是不可变类,推荐作为 Key);
      • 若必须用可变类,修改前先从 HashMap 中删除旧 Key。

四、ConcurrentHashMap 大厂真题解析

1. JDK7 与 JDK8 的 ConcurrentHashMap 实现有何区别?(腾讯真题)
  • 考点:分段锁 vs 细粒度锁,数据结构演进。
  • 满分答案
特性JDK7(分段锁)JDK8(CAS + 细粒度锁)
数据结构Segment 数组(每个 Segment 是小 HashMap)数组 + 链表 + 红黑树(同 HashMap 结构)
锁机制对 Segment 加 ReentrantLock(锁粒度大)对链表头节点或红黑树根节点加 synchronized(锁粒度小)
插入逻辑锁 Segment 后遍历链表先 CAS 无锁插入,失败后加锁
并发度受限于 Segment 数量(默认 16)理论并发度更高(锁竞争更小)
内存效率每个 Segment 有独立数组,内存占用略高共享数组,内存更紧凑
  • 典型场景
    JDK8 在高并发写入场景(如秒杀系统的计数器)性能提升显著,因锁粒度从 “段” 细化到 “节点”,减少线程竞争。
2. ConcurrentHashMap 为什么不允许 Key 和 Value 为 null?(美团真题)
  • 考点:线程安全与 null 值的歧义性。
  • 满分答案
    历史原因
    • HashMap 允许 null Key(唯一)和 null Value,ConcurrentHashMap 为避免与 Hashtable(不允许 null)行为不一致,选择不允许 null;
    • 更重要的是,null 值在多线程场景下存在歧义:
      • get(key)返回 null 时,无法区分 “Key 不存在” 和 “Value 为 null”;
      • 若允许 null Value,多线程插入时可能出现 “Key 存在但 Value 为 null” 的中间状态,导致后续读取误判。
        对比 HashMap
        HashMap 单线程下可明确处理 null(Key 只能有一个 null,Value 可为多个 null),但 ConcurrentHashMap 作为线程安全类,需避免这种歧义性,保证语义清晰。

五、面试真题陷阱与避坑指南

1. 设计原则陷阱题:“所有类都应该遵守单一职责原则吗?”(字节跳动)
  • 陷阱:考察对原则的灵活应用,而非教条主义。
  • 正确回答
    不是。单一职责原则的 “职责” 是 “变化的原因”,若多个职责不会同时变化(如 “用户校验” 和 “日志记录” 在项目中始终一起修改),可暂时合并以减少类数量。原则需结合项目规模和变化频率权衡,避免过度设计。
2. HashMap 扩容陷阱:“初始容量设为 10,实际数组长度是多少?”(阿里)
  • 陷阱:HashMap 会将容量自动调整为≥给定值的最小 2 的幂(10→16)。
  • 正确回答
    实际长度为 16。HashMap 的构造函数会调用tableSizeFor(int cap)方法,将容量向上取整为 2 的幂,确保(n-1)&hash的计算正确性。

面试扩展:

1. 设计原则综合题:“MVC 架构是否符合开闭原则?为什么?”
  • 考点:架构与设计原则的结合,扩展性分析。
  • 预测答案
    部分符合
    • View 层(如 Activity)常因 UI 变化直接修改,违反 “对修改关闭”;
    • Model 层(数据模型)和 Controller 层(逻辑处理)可通过抽象接口扩展(如新增数据源时实现新 Model 接口),符合 “对扩展开放”。
      改进建议
      引入接口隔离,让 View 依赖抽象(如 MVP 中的 View 接口),减少对具体实现的修改,更贴近开闭原则。
2. HashMap 深度陷阱题:“键的 hashCode () 返回 0,会发生什么?如何优化?”
  • 考点:极端哈希冲突处理,红黑树阈值。
  • 预测答案
    • 所有键存入数组的 0 号位置,形成长链表(或红黑树);
    • 若数组容量≥64 且链表长度≥8,转为红黑树,查询时间复杂度 O (logn);
    • 优化:重写 hashCode (),让键的哈希值更分散(如结合多个字段计算哈希)。

六、总结

知识点高频问题示例核心考点满分答案关键要素
单一职责原则如何拆分 Android 中的网络模块?职责定义(变化原因)、实际案例拆分前后对比,说明每个类的独立变化原因
DCL 单例为什么需要两次检查和 volatile?线程安全、指令重排、可见性结合源码解释两次检查的作用,volatile 的必要性
HashMap 红黑树链表转红黑树的条件是什么?阈值设计、概率分析、性能权衡同时满足长度≥8 和容量≥64,避免小树维护开销
ConcurrentHashMap与 Hashtable 的区别?锁机制、null 支持、并发度细粒度锁 vs 全表锁,弱一致性设计
设计原则与集合类核心考点  
├─ 设计原则(6大原则)  
│  ├─ SRP:职责=变化原因,拆分类/模块  
│  ├─ OCP:通过抽象扩展,避免修改原有代码  
│  ├─ LSP:子类可替换父类,不破坏契约  
│  ├─ ISP:接口细化,客户端不依赖无用方法  
│  ├─ DIP:高层模块依赖抽象,而非具体实现  
│  └─ LoD:仅与直接朋友交互,减少耦合  
├─ DCL单例  
│  ├─ 双重检查+volatile:防指令重排,线程安全  
│  ├─ 防御反射/反序列化:构造函数检查+readResolve  
│  └─ 最佳实践:枚举单例(最简、最安全)  
├─ HashMap  
│  ├─ 底层:数组+链表(≥8转红黑树,容量≥64)  
│  ├─ 哈希计算:高位异或,减少冲突  
│  ├─ 扩容:容量翻倍,重新哈希(初始容量设为2的幂)  
│  └─ Key要求:重写hashCode/equals,不可变类最佳  
└─ ConcurrentHashMap  ├─ 线程安全:JDK8细粒度synchronized+CAS  ├─ 与HashMap区别:不允许null,弱一致性  └─ 适用场景:高并发读写,替代Hashtable/同步HashMap  

相关文章:

  • NPP库中libnppc模块介绍
  • [原创](现代Delphi 12指南):[macOS 64bit App开发]: [1]如何加载动态链接库, 并无缝支持原生底层开发?
  • QpushButton 扩展InteractiveButtonBase
  • 【中间件】brpc_基础_remote_task_queue
  • AI功能测试源码AI聊天AI视觉AI图像AI视频AI画外音写作助手AI测试多语言无加密源码
  • 企业架构革新指南:中台的定义、实践与未来
  • 供应链算法整理(二)--- 智能补货
  • 哈夫曼树和哈夫曼编码
  • 【自存】python使用matplotlib正常显示中文、负号
  • 智能工厂边缘计算:从数据采集到实时决策
  • 【Linux】SELinux 的基本操作与防火墙的管理
  • 力扣-链表-2 两数相加
  • 课程10. 聚类问题
  • js逆向绕过指纹识别
  • 5个情感丰富GPT-4o图像提示词(不是吉卜力风格)
  • PyTorch数据集与数据集加载
  • 情绪ABC——AI与思维模型【93】
  • Semaphore的详细源码剖析
  • 组合模式深度解析:构建灵活树形结构的终极指南
  • 变更需求代价:影响分析
  • 苏杯登顶看到老将新人冲劲,国羽用冠军为奥运新周期开好头
  • 菲律宾首都机场航站楼外发生汽车冲撞事故致2死多伤
  • 工信部:加强通用大模型和行业大模型研发布局
  • AI把野史当信史?警惕公共认知的滑坡
  • 乌美矿产协议文本公布,明确乌收益及协议优先级
  • 受天气等影响SC8041航班三次备降延误超12小时,山航致歉