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  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/81892.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenHarmony GPIO应用开发-LED

学习于: https://docs.openharmony.cn/pages/v5.0/zh-cn/device-dev/driver/driver-platform-gpio-develop.md https://docs.openharmony.cn/pages/v5.0/zh-cn/device-dev/driver/driver-platform-gpio-des.md 通过OpenHarmony官方文档指导可获知:芯片厂…

XILINX原语之——xpm_fifo_async(异步FIFO灵活设置位宽、深度)

目录 一、"fwft"模式(First-Word-Fall-Through read mode) 1、写FIFO 2、读FIFO 二、"std"模式(standard read mode) 1、写FIFO 2、读FIFO 调用方式和xpm_fifo_sync基本一致: XILINX原语之…

系统学习算法:动态规划(斐波那契+路径问题)

题目一: 思路: 作为动态规划的第一道题,这个题很有代表性且很简单,适合入门 先理解题意,很简单,就是斐波那契数列的加强版,从前两个数变为前三个数 算法原理: 这五步可以说是所有…

《让内容“活”起来:Flutter社交应用瀑布流布局的破界实践》

用户动态的展示方式如同舞台的布景,直接影响着观众——用户的体验。而瀑布流布局,以其独特的美感和高效的信息展示能力,成为众多社交应用的心头好。当我们滑动着Instagram、Pinterest,或是国内热门的小红书,那种内容如…

微机控制技术复习【一】

填空题: 简答题: 1、什么是计算机控制系统?其典型形式有哪些? 2、给出 DDC (直接数字控制)控制系统结构框图,并说明各组成部分的作用? 3、采样周期选择的理论依据是什么?工程应用中应如何选择?选择采样…

前端学习基础—VScode环境配置及html基础知识

作为初学者,一个好的开发环境能极大地提高理解与学习的效率,本文分享我的VScode环境配置方法,涵盖插件、主题、快捷键等,希望能助你快速搭建舒适边界的前端学习环境。 一、VSCode环境配置 首先找到vscode插件商店,在这…

【一】 基本概念与应用领域【830数字图像处理】

考纲 文章目录 1 概念2005甄题【名词解释】2008、2012甄题【名词解释】可考题【简答题】可考题【简答题】 2 应用领域【了解】2.1 伽马射线成像【核医学影像】☆2.2 X射线成像2.3 紫外波段成像2.4 可见光和红外波段成像2.5 微波波段成像2.6 无线电波段成像2.7 电子显微镜成像2…

QuecPython错误码汇总

QuecPython中定义的各种错误代码常量 错误码常量错误码释义QUEC_PY_FAIL-1Generic failure codesQUEC_PY_OK0Quec_py value indicating success (no error)QUEC_PY_EPERM1Operation not permittedQUEC_PY_ENOENT2No such file or directoryQUEC_PY_ESRCH3No such processQUEC_…

C++学习-入门到精通-【4】函数与递归入门

C学习-入门到精通-【4】函数与递归入门 函数与递归入门 C学习-入门到精通-【4】函数与递归入门一、 数学库函数sqrt()ceil()cos()exp()fabs()floor()fmod()log()log10()pow()sin()tan()总结 二、具有多个形参的函数定义三、函数原型、函数签名和实参的强制类型转换函数原型函数…

天线测试报告解读学习

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、无源测试和有源测试二、无源测试报告1.驻波2.回损3.史密斯圆图4.效率5.增益6.天线方向图7.天线隔离度8.无源测试总结 三、有源测试报告1.TRP与TIS2.测试指标…

GEC6818蜂鸣器驱动开发

相关知识&#xff1a;Linux设备驱动开发 insmod 编译好的.ko文件后再运行beep_app.c编译完成的可执行文件即可使板子蜂鸣。 beep_drv.c: #include <linux/module.h> //包含了加载模块时需要使用的大量符号和函数声明 #include <linux/kernel.h> //包含了printk内…

电脑定时管家!Wise Auto Shutdown 深度测评:多任务执行 + 灵活定时

各位电脑小达人&#xff0c;今天给大家介绍一款超厉害的Windows系统定时任务管理工具——Wise Auto Shutdown&#xff01;这玩意儿就像电脑的贴心小管家&#xff0c;能自动执行关机、重启这些操作&#xff0c;时间设定灵活得很&#xff0c;还有提醒机制呢。下面我给大家好好唠唠…

vscode 配置qt

工具&#xff1a;vscode、qttools、qtconfigure Search Mode改成基于cmake的。 # 在项目中指定Qt的路径 set(Qt5_DIR "/home/jp/qt-everywhere-src-5.12.9/arm-qt/lib/cmake/Qt5") # 用于指定 Qt5 的安装路径 find_package(Qt5 REQUIRED COMPONENTS Widgets)这样就…

基于Boost库、Jsoncpp、cppjieba、cpp-httplib等构建Boost搜索引擎

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;项目 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 项目背景技术栈和项目环境正排索引和倒排索引数据去标签与清洗下载数据源去标签 建立索引构建正排索引构建倒排索引 建立搜索引擎h…

QMK机械键盘固件开发指南:从源码到实践

QMK机械键盘固件开发指南&#xff1a;从源码到实践 前言 QMK&#xff08;Quantum Mechanical Keyboard&#xff09;是一款开源的键盘固件&#xff0c;支持众多自定义键盘的功能配置。通过QMK&#xff0c;您可以完全掌控键盘的每一个按键&#xff0c;实现复杂的宏指令、多层按…

WPF 导航

WPF 导航相关控件/机制 控件 / 类说明常用属性/方法Frame用来承载不同的页面 (Page) 并在它们之间切换的容器。Source&#xff08;导航到的 URI&#xff09; Navigate()&#xff08;导航方法&#xff09; CanGoBack / GoBack() CanGoForward / GoForward()Page表示一个单独的可…

时序建模演进之路:从 MLP、RNN 到 LSTM 与 GRU

时序建模演进之路&#xff1a;从 MLP、RNN 到 LSTM 与 GRU 您是否好奇机器如何能像人类一样理解、生成流畅的文本&#xff0c;甚至是从海量代码中自动生成文档&#xff1f;这些自然语言处理 (NLP) 领域的迷人挑战&#xff0c;其核心在于模型处理和记忆 序列数据 的能力。 然而…

【Redis——数据类型和内部编码和Redis使用单线程模型的分析】

文章目录 Redis的数据类型和内部编码单线程模型的工作过程Redis在处理命令时虽然是一个单线程模型&#xff0c;为啥效率那么高&#xff0c;速度快呢&#xff1f; 总而言之&#xff0c;Redis提供的哈希表容器并不一定真的是真的哈希表&#xff0c;而是在特点的场景下&#xff0c…

鸿蒙NEXT开发动画(风格的旋转加载动画组件)

1.创建空白项目 2.Page文件夹下面新建Spin.ets文件&#xff0c;代码如下&#xff1a; /*** SpinKit 风格的旋转加载动画组件。** component* param spinSize - 动画容器大小&#xff08;必须为正数&#xff09;* param spinColor - 动画颜色&#xff08;支持资源引用&#xf…

后端接口请求http改为https

1、使用 OpenSSL 生成自签名证书 在Linxu服务器上执行如下命令&#xff1a; openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes 运行此命令后&#xff0c;会提示输入一些信息&#xff08;如国家、省份、城市、组织名称等&#xff09;&…