前言
在技术面试中,基础知识的扎实程度往往决定了能否通过初筛。本文整理了阿里、腾讯、字节、华为、百度等互联网大厂 Android 开发岗位的高频面试题,涵盖 Java 基础、并发编程、JVM、Android 体系架构、View 系统、Framework 及性能优化等核心领域。旨在帮助开发者系统复习技术栈,查漏补缺,提升面试通过率。
一、Java 基础相关
1.1 数据结构与算法
常用数据结构:
主要包括数组、链表、栈、队列、哈希表、树(二叉树、红黑树)、图等。面试中常考察其底层实现及适用场景。
数组操作:
- 查找丢失数字: 利用异或运算或求和公式,时间复杂度 O(n)。
- 查找重复数字: 快慢指针法(类似环形链表检测)或排序后遍历。
- 最大值最小值: 一次遍历比较,减少比较次数。
- 大数相加: 模拟竖式加法,处理进位,注意字符串转整数边界。
链表:
- 单链表反转: 迭代法需维护三个指针(prev, curr, next),递归法需注意栈溢出风险。
- 判断环: 快慢指针,若相遇则存在环,再从头开始同步移动可找到入环点。
- 合并两个有序链表: 递归或迭代,比较节点值选择较小者。
树与图:
- 二叉树遍历: 前序(根左右)、中序(左根右)、后序(左右根)。递归实现简单,迭代需用栈。
- 平衡二叉树: 任意节点左右子树高度差不超过 1。红黑树是近似平衡的二叉搜索树,保证最坏情况下的查找效率。
- B 树/B+ 树: 数据库索引常用结构,B+ 树非叶子节点不存数据,适合范围查询。
排序算法:
- 快速排序: 平均 O(nlogn),不稳定,原地排序。
- 堆排序: 利用堆结构,O(nlogn),不稳定。
- 归并排序: 稳定,需要额外空间。
- Top-K 问题: 通常使用小顶堆或快速选择算法(QuickSelect)解决。
1.2 Java 基础
内存模型与 GC:
- JVM 内存区域: 程序计数器、虚拟机栈、本地方法栈、堆、方法区。对象主要分配在堆上。
- GC 回收机制: 分代收集理论(新生代/老年代)。新生代用复制算法,老年代用标记 - 清除或标记 - 整理。
- 对象晋升: 对象年龄增长、大对象直接进入老年代、动态年龄判定。
- 引用类型: 强引用、软引用、弱引用、虚引用。用于控制对象生命周期,避免内存泄漏。
String 与集合:
- String 不可变: 设计为 final,利于缓存池、线程安全及 Hash 计算。
- HashMap 原理: JDK1.8 前为数组 + 链表,JDK1.8 后引入红黑树。扩容时重新 Hash,负载因子默认 0.75。
- ConcurrentHashMap: JDK1.7 分段锁,JDK1.8 CAS+synchronized,保证高并发下读写效率。
并发编程:
- synchronized: 关键字,JDK1.6 后优化为偏向锁、轻量级锁、重量级锁。保证原子性、可见性、有序性。
- volatile: 保证可见性,禁止指令重排,但不保证原子性。常用于状态标志位。
- AQS: AbstractQueuedSynchronizer,ReentrantLock 等锁的底层框架,基于 FIFO 队列和 state 变量。
- 线程池: 核心参数包括 corePoolSize, maximumPoolSize, workQueue 等。推荐自定义线程池而非使用 Executors。
- ThreadLocal: 线程隔离变量,原理是每个线程持有 ThreadLocalMap。注意内存泄漏问题,需手动 remove。
1.3 网络编程
- TCP 三次握手: SYN -> SYN+ACK -> ACK。防止失效连接请求,同步序列号。
- 四次挥手: FIN -> ACK -> FIN -> ACK。确保双方数据传输完成。
- HTTP vs HTTPS: HTTPS 在 HTTP 基础上加入 SSL/TLS 加密层,保证传输安全。
- URL 输入到页面展示: DNS 解析 -> TCP 连接 -> 发送 HTTP 请求 -> 服务器处理 -> 返回响应 -> 浏览器渲染。
二、Android 体系
2.1 Activity 生命周期
- 标准流程: onCreate -> onStart -> onResume -> onPause -> onStop -> onDestroy。
- 启动模式: standard, singleTop, singleTask, singleInstance。影响任务栈中 Activity 的创建与复用逻辑。
- 保存状态: onSaveInstanceState 用于配置变更时的临时保存,onSaveInstanceState 数据在重启后会恢复。
2.2 Service 与 Broadcast
- Service 生命周期: startService (onStartCommand) 与 bindService (onBind) 两种模式。
- IntentService: 继承自 Service,内部有 HandlerThread 处理异步任务,执行完自动停止。
- BroadcastReceiver: 静态注册在 Manifest,动态注册在代码。有序广播按优先级顺序执行,普通广播并行。
2.3 Context 区别
- Application: 应用全局上下文,生命周期最长,不能启动 Activity。
- Activity: 包含 UI 信息,可启动其他组件,但易导致内存泄漏。
- Service: 服务上下文,主要用于后台任务。
三、View System
3.1 绘制流程
- Measure: 确定 View 宽高。父容器传递 spec,子 View 根据 spec 计算自身大小。
- Layout: 确定 View 位置。调用 onLayout 设置子 View 坐标。
- Draw: 绘制内容。分为 drawBackground, dispatchDraw, drawChildren, onDraw。
- invalidate vs postInvalidate: 主线程刷新用 invalidate,子线程刷新用 postInvalidate。
3.2 事件分发机制
- 责任链模式: DispatchTouchEvent -> OnInterceptTouchEvent -> onTouchEvent。
- 冲突解决: requestDisallowInterceptTouchEvent 可请求父布局不要拦截事件;CustomView 重写 onInterceptTouchEvent。
3.3 RecyclerView 优化
- 复用机制: ViewHolder 复用,避免频繁 findViewById。
- 预加载: 提前加载下一页数据,减少滑动卡顿。
- 局部刷新: 使用 DiffUtil 计算差异,仅更新变化部分。
四、Android Framework
4.1 Binder 机制
- 原理: 跨进程通信 IPC 机制。Client -> Driver -> Server。内核驱动提供共享内存映射。
- 线程池: Binder 线程池管理,避免频繁创建销毁线程。
4.2 Handler 消息机制
- 流程: Handler.sendMessage -> MessageQueue -> Looper.loop -> MessageTarget.dispatchMessage -> Callback/HandleMessage。
- Looper: 每个线程一个 Looper,循环从 MessageQueue 取消息。主线程 Looper 初始化由 Application 完成。
- ANR: 主线程阻塞超过 5 秒触发。常见于主线程进行 IO 或复杂计算。
4.3 存储方式
- SharedPreferences: XML 存储,适合轻量配置。commit 同步写入,apply 异步写入。
- SQLite: 关系型数据库,支持 SQL 查询。
- Room: SQLite 抽象层,编译时检查 SQL 正确性。
五、性能优化专题
5.1 启动速度优化
- 延迟初始化: 非必要组件延后加载。
- 异步加载: 图片、数据异步获取。
- 减少主线程耗时: 避免 IO、网络、复杂计算在主线程。
5.2 内存优化
- LeakCanary: 检测内存泄漏工具。
- Bitmap 压缩: 根据屏幕密度加载合适尺寸图片,及时 recycle。
- 静态引用: 避免在静态字段中持有 Context。
5.3 包体积优化
- ProGuard/R8: 代码混淆与压缩。
- 资源瘦身: 移除无用资源,使用矢量图替代位图。
- 多 ABI 支持: 按需打包 so 库。
六、三方源码理解
6.1 Glide
- 加载流程: Request -> ModelLoader -> DataFetcher -> Transformation -> Target。
- 缓存策略: 内存缓存 + 磁盘缓存。LRU 算法管理缓存大小。
6.2 Retrofit
- 原理: 动态代理生成接口实现类。OkHttp 负责网络请求,Converter 负责序列化。
- 线程切换: 配合 RxJava 或 Executor 实现线程调度。
6.3 EventBus
- 发布订阅模式: 解耦组件间通信。注意内存泄漏,需在合适时机 unregister。
总结
面试不仅是知识点的考察,更是逻辑思维与问题解决能力的体现。建议将上述知识点结合源码深入理解,并通过实际项目验证。保持持续学习的心态,定期复盘,才能在激烈的竞争中脱颖而出。祝各位开发者都能拿到理想的 Offer!