跳到主要内容Android 高级工程师面试核心知识点与高频题库解析 | 极客日志Javajava算法
Android 高级工程师面试核心知识点与高频题库解析
Android 高级工程师面试涵盖 Java 基础、集合、多线程、虚拟机、四大组件、Handler 机制、AMS、Binder、音视频及 Flutter 等内容。本文整理了高频面试题并提供详细解答,帮助开发者系统复习技术栈,掌握底层原理与实战场景,提升面试通过率。
深海蔚蓝2 浏览 Android 高级工程师面试核心知识点与高频题库解析
Java 基础部分
抽象类与接口的区别?
- 语法层面:接口只能定义常量、默认方法、静态方法和抽象方法;抽象类可以包含成员变量、构造器、普通方法。
- 继承关系:一个类可以实现多个接口,但只能继承一个抽象类。
- 设计目的:接口是对行为的抽象,用于定义规范;抽象类是对类的抽象,用于代码复用和模板设计。
- 访问修饰符:接口中的方法默认为 public abstract(Java 8+ 支持 default/static);抽象类方法可以是任意访问级别。
分别讲讲 final, static, synchronized
- final:修饰类表示不可继承,修饰方法表示不可重写,修饰变量表示常量(基本类型值不变,引用类型地址不变)。
- static:修饰成员属于类而非实例,可通过类名直接访问,常用于工具方法或常量。
- synchronized:关键字,用于保证多线程环境下的线程安全,可修饰方法或代码块,实现互斥锁机制。
String、StringBuffer 和 StringBuilder 的区别
- String:不可变字符序列,每次修改都会生成新对象,适合少量字符串操作。
- StringBuffer:可变字符序列,线程安全(方法加锁),性能较低,适合多线程环境。
- StringBuilder:可变字符序列,非线程安全,性能较高,适合单线程大量字符串拼接。
equals 与 ==、hashCode 的区别和使用场景
- ==:比较基本类型的值或对象的内存地址。
- equals():默认比较地址,Object 子类通常重写以比较内容(如 String)。
- hashCode():返回哈希码,用于哈希表(HashMap)快速定位。若重写 equals 必须重写 hashCode,且相等对象的 hashCode 必须相同。
Java 中深拷贝与浅拷贝的区别
- 浅拷贝:复制对象本身,但引用类型字段仍指向原对象内存地址。
- 深拷贝:完全复制对象及其引用的所有对象,新旧对象无关联。
Error 和 Exception 的区别
- Error:系统级错误,如 OutOfMemoryError,程序无法处理,通常不捕获。
- Exception:程序运行异常,分为受检异常(Checked)和非受检异常(Runtime),建议捕获处理。
什么是反射机制?应用场景?
- 定义:在运行时动态获取类的信息(属性、方法、构造器)并操作对象的能力。
- 场景:框架开发(Spring IOC/AOP)、动态代理、序列化/反序列化、插件化架构。
如何重写 equals() 方法?为什么还要重写 hashCode()?
- 重写 equals:通常使用 IDE 生成,需遵循自反性、对称性、传递性、一致性、非空性原则。
- 重写 hashCode:因为 HashMap 等集合依赖 hashCode 确定存储位置。若 equals 相等但 hashCode 不同,会导致集合无法正确识别对象重复。
Java 泛型中类型擦除的理解及局限性
- 原理:编译期将泛型替换为原始类型(如 T 替换为 Object),并插入强制转换代码。
- 局限性:无法判断泛型具体类型(如
new T() 非法),无法创建泛型数组,无法区分泛型参数类型。
String 为什么要设计成不可变的?
- 安全性:作为 Key 存储在 Map 中不会被篡改。
- 线程安全:无需同步即可共享。
- 缓存优化:字符串常量池可复用,减少内存开销。
- 哈希缓存:hashCode 计算一次后可缓存。
对 Java 注解的理解
- 定义:元数据,提供代码以外的信息,编译器或运行时可读取。
- 用途:编译检查(@Override)、代码生成(Lombok)、框架配置(@Autowired)。
Java 集合
List, Set, Map 的区别
- List:有序、可重复,索引访问(ArrayList, LinkedList)。
- Set:无序、不可重复(HashSet, TreeSet)。
- Map:键值对存储,Key 唯一(HashMap, TreeMap)。
ArrayList 和 LinkedList 的区别
- ArrayList:基于数组,随机访问快 O(1),增删慢(需移动元素)。
- LinkedList:基于双向链表,随机访问慢 O(n),增删快(只需修改指针)。
HashMap 与 HashTable 的区别
- 线程安全:HashTable 全方法同步,HashMap 非同步(ConcurrentHashMap 更安全)。
- Null 值:HashTable 不允许 null key/value,HashMap 允许。
- 迭代器:HashTable 是 Enumeration,HashMap 是 Iterator。
ArrayList 的扩容机制
- 初始容量 10,当元素数量超过容量 * 负载因子(0.75)时,扩容为原来的 1.5 倍,并重新哈希分配。
HashMap 的实现原理
- 结构:数组 + 链表 + 红黑树(JDK 1.8+)。
- 流程:计算 hash -> 定位桶 -> 若冲突则链表头插法(JDK 1.7 尾插,1.8 头插)-> 链表长度超阈值转红黑树 -> 触发扩容。
LinkedHashMap 的工作原理
- 继承自 HashMap,维护双向链表记录插入顺序或访问顺序,遍历效率高于 HashMap。
ConcurrentHashMap 的理解
- JDK 1.7:分段锁(Segment),并发度等于 Segment 数量。
- JDK 1.8:Node 数组 + 链表/红黑树,锁粒度细化到桶(CAS + synchronized),并发度更高。
Java 多线程
Java 中使用多线程的方式
- 继承 Thread 类。
- 实现 Runnable 接口。
- 实现 Callable 接口(配合 FutureTask)。
- 使用线程池(ExecutorService)。
线程的几种状态
- NEW(新建)、RUNNABLE(运行/就绪)、BLOCKED(阻塞等待锁)、WAITING(无限等待)、TIMED_WAITING(限时等待)、TERMINATED(终止)。
如何实现多线程中的同步
- 使用 synchronized 关键字、Lock 接口(ReentrantLock)、volatile 关键字、原子类(AtomicInteger)。
线程死锁及避免
- 死锁:两个或多个线程互相持有对方需要的资源,导致永久等待。
- 避免:按固定顺序获取锁、设置超时时间、使用 Lock.tryLock()。
线程阻塞的原因
- 等待 I/O、等待锁、调用 sleep/wait、主动 yield 等。
Thread 中 run() 与 start() 的区别
- start():启动新线程,自动调用 run()。
- run():普通方法调用,在当前线程执行,不启动新线程。
synchronized 和 volatile 的区别
- synchronized:保证原子性、可见性、有序性,重量级锁。
- volatile:仅保证可见性和有序性,不保证原子性,轻量级。
如何保证线程安全
- 不可变对象、线程封闭、同步控制、原子类、ThreadLocal。
ThreadLocal 用法和原理
- 用法:每个线程拥有独立的变量副本,常用于数据库连接管理。
- 原理:Thread 内部维护 ThreadLocalMap,Key 为 ThreadLocal 实例,Value 为绑定值。
notify 和 notifyAll 的区别
- notify:唤醒一个等待线程(随机)。
- notifyAll:唤醒所有等待线程,竞争锁。
线程池及创建
- 作用:复用线程,降低开销,控制并发数。
- 创建:Executors.newFixedThreadPool(), newCachedThreadPool(), newSingleThreadExecutor() 或使用 ThreadPoolExecutor 自定义参数。
java 线程常见的几种锁
- ReentrantLock(可重入)、ReadWriteLock(读写分离)、StampedLock(乐观读)、Synchronizer(AQS)。
sleep() 和 wait() 的区别
- sleep:Thread 静态方法,不释放锁,指定时间后自动恢复。
- wait:Object 方法,释放锁,需 notify/notifyAll 唤醒。
Java 虚拟机
JAVA 垃圾回收机制
- 自动管理内存,通过标记 - 清除、复制、标记 - 整理、分代收集等算法回收无用对象。
强、软、弱、虚引用区别
- 强引用:常见引用,GC 不回收。
- 软引用:内存不足时回收,用于缓存。
- 弱引用:GC 立即回收,用于临时对象。
- 虚引用:无法获取对象,仅用于跟踪对象回收状态(Finalizer)。
JVM 中类的加载机制与过程
- 加载:二进制流读入内存。
- 验证:确保字节流符合规范。
- 准备:分配内存并设零值。
- 解析:符号引用转直接引用。
- 初始化:执行
<clinit> 方法。
JVM、Dalvik、ART 三者的原理和区别
- JVM:标准 Java 虚拟机,解释 + JIT 编译。
- Dalvik:Android 早期虚拟机,基于寄存器,即时编译(JIT)。
- ART:Android 4.4+,预编译(AOT),启动快但安装慢,内存占用高。
JMM 是什么?问题与解决
- Java 内存模型:定义线程与主内存交互规则。
- 问题:可见性、原子性、指令重排。
- 解决:volatile、synchronized、Lock、原子类。
Android 方面
Activity 与 Fragment 通信方式
- Interface 回调、BroadcastReceiver、EventBus、ViewModel(推荐)、Bundle 传参。
LaunchMode 的应用场景
- standard:默认,每启动创建新实例。
- singleTop:栈顶复用。
- singleTask:栈内复用,清除上层任务。
- singleInstance:独立栈,全局单例。
Context 了解多少
- 上下文,提供资源访问、组件启动、服务绑定等功能。有 Application、Activity、Service 三种,注意内存泄漏风险。
IntentFilter 及使用场景
- 声明组件能响应的 Action、Category、Data,用于隐式 Intent 匹配,如接收广播、打开网页。
startService 和 bindService 的区别
- startService:生命周期独立,停止需 stopService。
- bindService:生命周期绑定,解绑后服务销毁,适合短连接交互。
Service 保活
- 前台服务、JobScheduler、AlarmManager、双进程守护、系统白名单等。
ContentProvider 数据共享
- 封装数据源,提供统一接口 CRUD,跨进程数据共享(如通讯录)。
横竖屏切换 Activity 生命周期
- onConfigurationChanged 拦截前:onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume。
- 拦截后:仅 onConfigurationChanged。
Intent 传输数据限制及解决
- 限制:Binder 单次传输约 1MB。
- 解决:传递 URI、使用 FileProvider、拆分数据、使用 SharedPreferences。
Android 异步任务和消息机制
HandlerThread 的使用场景
- 需要后台线程且需 Looper 的场景,如下载、网络请求。
IntentService 的应用场景
- 处理一次性异步任务,执行完自动停止,自带 WorkerThread。
AsyncTask 优缺点
- 优点:简化异步,自动回调 UI。
- 缺点:内存泄漏风险,Android 11+ 已废弃,不支持长时间任务。
Activity.runOnUiThread 理解
- 在主线程执行 Runnable,内部通过 Handler 发送 Message 实现。
子线程能否更新 UI?为什么?
- 不能。UI 线程(MainLooper)负责绘制,子线程更新会导致崩溃或显示异常。
Handler 机制和原理
- MessageQueue:队列存储消息。
- Looper:循环取消息。
- Handler:发送和处理消息,将 Message 入队或回调。
子线程创建 Handler 抛异常原因
- 子线程没有 Looper,调用 Looper.prepare() 未执行,导致 MessageQueue 为空。
Loop 死循环为何不阻塞主线程
- Looper.loop() 中调用 MessageQueue.next() 会进入 native 层阻塞(poll),收到消息才唤醒,CPU 空闲。
数据结构
冒泡排序及优化
- 相邻元素交换,O(n^2)。优化:设置标志位,若一轮无交换则提前结束。
单链表实现
- 定义 Node 类(val, next),实现 add、delete、traverse 方法。
反转单链表
- 头插法或三指针法(prev, curr, next)迭代实现。
时间复杂度和空间复杂度
- 时间:算法执行所需时间,关注增长趋势(O(n))。
- 空间:算法执行所需额外内存。
判断链表成环
红黑树及原因
- 自平衡二叉查找树,高度近似 log n。HashMap 用红黑树防止链表过长导致查询退化为 O(n)。
快速排序及优化
- 分治思想,选基准分区。优化:三数取中、小数组插入排序。
循环队列
- 数组首尾相接,解决假溢出,front/rear 指针模运算。
判断单链表交叉
Android Framework
Binder 优势
- 高效 IPC,一次拷贝,权限控制,支持多进程通信。
Binder 一次拷贝原理
- 利用 mmap 映射内核缓冲区,用户态直接读写内核内存,减少 copy_from_user/copy_to_user。
MMAP 内存映射原理
- 将文件/设备映射到虚拟地址空间,进程可直接访问,无需系统调用拷贝。
Binder 跨进程机制
- Client -> Service Manager -> Server,通过 Binder Driver 在内核层传递句柄和数据。
四大组件通信机制
- Activity/Service/ContentProvider 通过 Binder;Broadcast 通过 Intent。
Intent 大数据限制
- Binder 限制 1MB,大文件需走 FileProvider 或 ContentProvider。
HandlerThread 存在原因
- 为特定线程创建 Looper,方便处理耗时任务且能响应消息。
Looper 存在哪?线程独有?
- 存在于 Thread 局部变量(ThreadLocal)。主线程 init 时创建,子线程需手动 prepare。
ThreadLocal 作用
Main Looper 与一般 Looper 异同
- 主线程 Looper 由 System.init 创建,其他线程需手动创建。
Handler 切换线程
- 使用 HandlerThread 或 Executor 创建带 Looper 的线程,在该线程创建 Handler。
Looper loop 不卡死原理
- 阻塞在 MessageQueue 的 native poll 上,无消息时休眠,有消息唤醒。
Message 获取与唤醒
- 通过 epoll_wait 等待事件,收到信号唤醒 poll,取出 Message 分发。
AMS 相关
- ActivityManagerService:系统服务,管理 Activity 栈、进程调度。
- ActivityThread:应用主线程入口,绑定 AMS。
- Instrumentation:监控应用行为,用于测试和调试。
- Zygote 通信:AMS 启动 Zygote 进程,Zygote fork 应用进程。
- Record/Stack:ActivityRecord 记录状态,TaskRecord 记录任务,ActivityStack 管理栈。
- 手写 AMS:模拟核心逻辑,包括启动流程、状态管理、IPC 通信。
算法方面
二分查找运用
接雨水问题
- 双指针或单调栈,计算每个位置左右最大高度的最小值减去当前高度。
最长回文子串
去除有序数组重复元素
模幂运算
- 快速幂算法,递归或迭代,时间复杂度 O(log n)。
贪心跳跃游戏
回文链表判定
随机抽取元素
括号合法性
缺失和重复元素
HashMap/SparseArray/ConcurrentHashMap
- HashMap:数组 + 链表 + 树,线程不安全。
- SparseArray:int 数组 + object 数组,针对 int key 优化,节省内存。
- ConcurrentHashMap:分段锁/CAS+Synchronized,线程安全。
Kotlin 方面
Kotlin 特性
- 简洁、空安全、协程、扩展函数、高阶函数、IDEA 友好。
单例实现
- object 关键字、Companion Object、双重检查锁(Java 兼容)。
内联函数
- inline 关键字,编译时将函数体展开,消除 Lambda 对象开销,提升性能。
Coroutines vs 线程
- Coroutine:轻量级,协作式,挂起恢复,高并发低资源。
- Thread:重量级,抢占式,OS 调度。
Any 与 Object
- Any:Kotlin 顶层父类,对应 Java Object。
- 差异:Kotlin 有 null 安全,Any 不能为 null,Nothing 表示无返回值。
数据类型隐式转换
- 不支持自动装箱拆箱,需显式调用 toInt() 等方法,避免歧义。
集合遍历方式
- for 循环、forEach、map、filter、let 等扩展函数。
let 原理
- 高阶函数,接收 lambda,this 为接收者,返回 lambda 结果。
run 原理
- 接收 lambda,this 为接收者,返回 lambda 最后一行表达式结果。
音视频方面
直播秒开优化
- 预加载、CDN 加速、HLS 切片优化、首帧关键帧策略。
数字图像滤波
图像特征提取
FFMPEG 图片合成视频
- ffmpeg -framerate 25 -i img%03d.jpg -c:v libx264 out.mp4
常见音视频格式
- MP4, MKV, AVI, MOV, FLV, WebM。
MPEG 视频码流结构
- Sequence Header -> GOP -> Frame (I/P/B)。
FFMPEG 数据结构
- AVFormatContext, AVStream, AVPacket, AVFrame。
延迟/卡顿/抖动优化
- 延迟:减小缓冲、选择低延迟协议(WebRTC)。
- 流畅:自适应码率、预缓冲。
- 抖动:抖动缓冲(Jitter Buffer)。
软解与硬解
- 软解:CPU 解码,兼容性好,耗电高。
- 硬解:GPU/专用芯片解码,效率高,省电,兼容性受限。
Flutter 方面
Dart 语言特性
- 面向对象、可选类型、异步编程(Future/Stream)、Hot Reload 支持。
Dart 多任务并行
- Isolate 实现真正并行,避免 GC 停顿,共享内存通过 SendPort。
值传递还是引用传递
- 值传递(按值传递引用),对象引用复制,修改对象内容影响原对象。
Flutter 特性
- 跨平台、热重载、声明式 UI、高性能渲染引擎(Skia)。
Widget, Element, RenderObject 关系
- Widget:配置描述(不可变)。
- Element:Widget 在树中的实例(可更新)。
- RenderObject:布局与绘制逻辑(实际渲染)。
Mixins 条件
- 类继承自 Object,使用 mixin 关键字组合功能,避免多重继承冲突。
Stream 订阅模式
- Listen:监听事件流,支持取消订阅。
- Transform:对数据进行转换过滤。
Widget, State, Context 概念
- Widget:UI 蓝图。
- State:可变数据。
- Context:访问环境和资源。
Hot Reload, Hot Restart, 热更新
- Reload:注入代码,保留状态,刷新 UI。
- Restart:重启应用,重置状态。
- 热更新:远程下发代码包,绕过审核(Flutter 需谨慎合规)。
Flutter 与原生通信
- Platform Channel(MethodChannel, EventChannel)。
状态管理
- 需求:解耦 UI 与数据,集中管理复杂状态。
- 方案:Provider, Riverpod, Bloc, GetX。
注:本文档整理了 Android 高级工程师面试的核心技术点,涵盖从底层原理到框架应用的全方位知识。建议结合源码阅读与实战项目深入理解。
相关免费在线工具
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online