Android 高级工程师面试:Java 基础知识 近1年高频追问 22 题
文章目录
- 学习建议
- 基础层(8 题)
- #1 `==` 和 `equals` 有什么区别? 🔥
- 标准回答
- 面试官可能继续追问
- #2 `equals` 和 `hashCode` 的契约是什么? 🔥
- 标准回答
- 面试官可能继续追问
- #3 `ArrayList` 和 `LinkedList` 怎么选? 🔥
- 标准回答
- 面试官可能继续追问
- #4 `HashMap` 的 `put`/`get` 流程? 🔥
- 标准回答
- 面试官可能继续追问
- #5 基本类型和包装类有什么区别? ⭐
- 标准回答
- 面试官可能继续追问
- #6 `String`、`StringBuilder`、`StringBuffer` 怎么选? ⭐
- 标准回答
- 面试官可能继续追问
- #7 接口和抽象类的区别? ⭐
- 标准回答
- 面试官可能继续追问
- #8 重载和重写的区别? ⭐
- 标准回答
- 面试官可能继续追问
- 进阶层(7 题)
- #9 `HashMap` 扩容与树化机制? 🔥
- 标准回答
- 面试官可能继续追问
- #10 `Comparable` 和 `Comparator` 有什么区别? ⭐
- 标准回答
- 面试官可能继续追问
- #11 `final` 关键字能修饰什么?有什么作用? ⭐
- 标准回答
- 面试官可能继续追问
- #12 checked 异常和 unchecked 异常怎么区分? ⭐
- 标准回答
- 面试官可能继续追问
- #13 `static` 成员在 Android 里要注意什么? ⭐
- 标准回答
- 面试官可能继续追问
- #14 Java 有哪几种内部类?各有什么特点? ⭐
- 标准回答
- 面试官可能继续追问
- #15 `SparseArray` 和 `HashMap` 怎么选? ⭐
- 标准回答
- 面试官可能继续追问
- 核心层(7 题)
- #16 `LruCache` 和 `HashMap` 怎么选? 🔥
- 标准回答
- 面试官可能继续追问
- #17 深拷贝和浅拷贝的区别? ⭐
- 标准回答
- 面试官可能继续追问
- #18 BIO 和 NIO 在 Android 网络中的视角? ⭐
- 标准回答
- 面试官可能继续追问
- #19 Java 8 lambda 在 Android 中如何工作? 💡
- 标准回答
- 面试官可能继续追问
- #20 `try-with-resources` 和 `AutoCloseable` 是什么? 💡
- 标准回答
- 面试官可能继续追问
- #21 Java 是值传递还是引用传递? 💡
- 标准回答
- 面试官可能继续追问
- #22 Java 8 `Stream` 在 Android 里能用吗? 💡
- 标准回答
- 面试官可能继续追问
- 面试策略速查
- 必背知识(🔥)
- 高频追问
- 加分项(💡)
- 容易踩坑
- 完整链路一句通
- 相关推荐
学习建议
| 目标层级 | 建议 |
|---|---|
| 初级 | 掌握基础层 8 题:==/equals、集合 API、String 选型;工程联想看追问第 1 条 |
| 中级 | 通读全文;进阶层能讲清 HashMap 扩容、final/异常体系、内部类分类 |
| 高级 | 核心层 LruCache/拷贝/lambda/Stream 必答;能串联「相等语义→集合选型→资源关闭」工程链路 |
基础层(8 题)
#1==和equals有什么区别? 🔥
标准回答
==比较引用是否同一对象,equals比较业务语义是否相等。equals默认同==,重写后按字段逻辑判断。
面试官可能继续追问
Android 里
==和equals怎么用?
比较Bitmap缓存 key 或自定义User对象时,必须明确用equals而非==,否则HashMap查不到或去重失败。String 用
==为什么有时为 true?
字面量进字符串池,同一字面量共享引用;new String()必为 false。重写
equals不重写hashCode会怎样?
相等对象哈希不同,HashMap/HashSet行为错乱,键值对「丢失」。
#2equals和hashCode的契约是什么? 🔥
标准回答
契约:equals相等则hashCode必须相同;hashCode相同对象可不等。HashMap先算哈希定位桶,再用equals比对链表/树节点。
面试官可能继续追问
Android 里
equals/hashCode注意什么?
自定义Parcelable数据类或 Room 实体作Map键时,用 IDE 生成二者,避免缓存命中失败。为什么
HashMap先比hashCode再比equals?
先缩小桶范围,减少全字段比较,O(1) 均摊依赖此两步。data class 自动生成够吗?
Kotlindata class已生成;Java 手写实体务必同步维护两方法。
#3ArrayList和LinkedList怎么选? 🔥
标准回答
ArrayList底层数组,随机访问 O(1),尾部增删均摊快;LinkedList双向链表,头尾插删快但随机访问慢。
面试官可能继续追问
Android 里
ArrayList和LinkedList怎么选?
列表数据几乎都用ArrayList或RecyclerView适配器数据源;LinkedList极少用,除非明确队列语义且规模可控。ArrayList扩容机制?
容量不足时约 1.5 倍扩容并拷贝,频繁扩容有分配开销。主线程遍历大
LinkedList会卡吗?
会,get(i)每次从头/尾遍历,大列表禁止随机索引访问。
#4HashMap的put/get流程? 🔥
标准回答
put:算hash扰动 → 定位桶 → 无冲突直接放;冲突则链表或红黑树插入,超阈值扩容。get:同定位桶,再equals匹配。
面试官可能继续追问
Android 里
HashMap怎么用?
临时 ID 映射、内存缓存键值对常用HashMap;需淘汰策略改LruCache(内部也是LinkedHashMap)。为什么容量建议取 2 的幂?
用(n-1) & hash代替取模,位运算更快且分布均匀。多线程能直接用
HashMap吗?
不能,并发写可能死循环或丢数据,用ConcurrentHashMap或加锁。
#5 基本类型和包装类有什么区别? ⭐
标准回答
局部变量中的基本类型在栈帧内;作为对象字段或数组元素时随对象在堆。包装类是对象,有额外头与装箱开销。int/Integer在 -128~127 有缓存池。
面试官可能继续追问
Android 里基本类型和包装类怎么选?
性能敏感路径(游戏循环、大量坐标计算)优先基本类型数组;泛型集合必须用包装类或 Kotlin 专用数组。自动装箱的坑?
循环里反复Integer装箱产生大量短生命周期对象,加重 GC。Kotlin 还有这个问题吗?
有,但可用IntArray等原生数组避免装箱。
#6String、StringBuilder、StringBuffer怎么选? ⭐
标准回答
String不可变,拼接产生中间对象;StringBuilder可变、非线程安全;StringBuffer线程安全但同步开销大。
面试官可能继续追问
Android 里 String 系列怎么选?
主线程拼 JSON、日志、SQL 用StringBuilder;常量文案用String;多线程共享拼接极少见,一般各线程本地StringBuilder。Kotlin 字符串拼接呢?
编译器优化为StringBuilder,简单+小量拼接可接受。String.intern()在 Android 慎用吗?
慎用,池在堆中,滥用占内存且版本行为差异大。
#7 接口和抽象类的区别? ⭐
标准回答
接口定义能力契约,Java 8+ 可有default/static方法;抽象类可有状态与构造器,单继承。
面试官可能继续追问
Android 里接口和抽象类怎么选?
OnClickListener是接口;RecyclerView.Adapter是抽象类承载模板方法。多实现用接口,共享基类逻辑用抽象类。为什么
Activity是类不是接口?
框架需统一生命周期与上下文实现,抽象类更合适承载模板。Kotlin 接口还能有属性吗?
可以有,但通常无 backing field,注意与 Java 互操作。
#8 重载和重写的区别? ⭐
标准回答
重载:同类同名不同参,编译期绑定。重写:子类覆盖父类实例方法,运行期多态。
面试官可能继续追问
Android 里重载和重写例子?
onCreate(Bundle)是重写;多个findViewById重载已随 ViewBinding 淡化。理解多态有助于读RecyclerView各类onBindViewHolder重写链。能重写
static方法吗?
不能,子类是隐藏(hide)而非多态重写。@Override有必要吗?
有必要,父类签名变更时编译期即可发现错误。
进阶层(7 题)
#9HashMap扩容与树化机制? 🔥
标准回答
负载因子默认 0.75,元素数超容量×0.75则翻倍扩容并 rehash。单桶链表长度 ≥8 且表容量 ≥64 时链表转红黑树,≤6 退化为链表,防哈希攻击与过长查找。
面试官可能继续追问
Android 里 HashMap 扩容注意什么?
大缓存HashMap应预估容量减少扩容;Profiler 看分配峰值是否来自频繁 rehash。为什么树化阈值是 8?
泊松分布下链表达 8 的概率极低,权衡树维护成本。扩容是线程安全的吗?
否,并发扩容可能导致 JDK7 环形链表问题,JDK8 改为尾插但仍非线程安全。
#10Comparable和Comparator有什么区别? ⭐
标准回答
Comparable是类内部自然排序(compareTo),如String、Integer;Comparator是外部比较器,可灵活定义多套规则。TreeMap/TreeSet、Collections.sort都依赖二者。
面试官可能继续追问
Android 里排序接口怎么用?
列表按时间、优先级排序时,实体实现Comparable或传入Comparator;DiffUtil比较项也常自定义Comparator逻辑。能用 lambda 写
Comparator吗?
可以,Comparator.comparing(User::getName)更简洁。compareTo返回 0 表示什么?
相等;TreeSet中返回 0 视为重复元素不插入。
#11final关键字能修饰什么?有什么作用? ⭐
标准回答
可修饰类(不可继承)、方法(不可重写)、字段(赋值一次)、局部变量(引用不可改指向)。
面试官可能继续追问
Android 里
final怎么用?final字段配合构造器可做不可变对象;匿名内部类访问外部局部变量要求final或 effectively final。final引用和不可变对象是一回事吗?
不是,final只保证引用不变,对象内容仍可能可变(如final List仍可add)。为什么 lambda 捕获的变量要 effectively final?
捕获的是值快照,允许隐式修改会破坏语义一致性。
#12 checked 异常和 unchecked 异常怎么区分? ⭐
标准回答
checked:编译期必须处理或声明抛出,如IOException;unchecked:继承RuntimeException或Error,如NullPointerException、IllegalArgumentException。
面试官可能继续追问
Android 里异常怎么处理?
现代代码倾向用 unchecked + 统一异常处理,IO 在边界层捕获转业务错误;不要在每个回调层层 throws。为什么有人反对 checked 异常?
样板代码多,与函数式/回调风格不契合。Retrofit 网络错误算哪种?
调用方通过onFailure处理,不强制 checked 传播。
#13static成员在 Android 里要注意什么? ⭐
标准回答
静态字段属于类,生命周期与进程一致,不能持有Activity/View等短生命周期 Context,否则易泄漏。静态方法无this,适合工具函数。静态块做类加载期初始化。
面试官可能继续追问
Android 里
static成员注意什么?Application级单例可用静态,但应持ApplicationContext而非Activity。静态变量存在哪?
类元数据区逻辑归属,所指对象实例仍在堆。静态方法能重写吗?
不能,子类是隐藏(hide)而非多态。
#14 Java 有哪几种内部类?各有什么特点? ⭐
标准回答
成员内部类(持外部类引用)、静态内部类(不持外部实例)、局部内部类(方法内)、匿名内部类(一次性实现接口/抽象类)。
面试官可能继续追问
Android 里内部类怎么选?
new OnClickListener(){}是匿名内部类;非静态内部类隐式持有外部类引用,长生命周期回调优先静态内部类 + 弱引用或改用 lambda/协程。为什么推荐静态内部类?
不隐式绑定外部Activity,生命周期更易控。lambda 和匿名内部类关系?
lambda 是更简洁的函数式写法,捕获this同样有持有外部类风险。
#15SparseArray和HashMap怎么选? ⭐
标准回答
SparseArray用两个数组存 int key 与 value,无装箱、内存更省,key 必须 int;HashMap通用但Integer键有装箱开销。
面试官可能继续追问
Android 里
SparseArray和HashMap怎么选?
SDK 大量用SparseArray/LongSparseArray替代Map<Integer, ?>,如View的 tag、监听器缓存;通用对象键仍用HashMap。查找复杂度?
SparseArray二分查找 O(log n);小数据常比HashMap更省。ArrayMap又是什么?
Android 对少量映射的数组实现,适合小集合。
核心层(7 题)
#16LruCache和HashMap怎么选? 🔥
标准回答
LruCache基于LinkedHashMap访问顺序,超容量自动淘汰最久未用条目,并可重写sizeOf按字节计;HashMap无淘汰。
面试官可能继续追问
Android 里
LruCache怎么用?
图片内存缓存、解析结果缓存用LruCache;临时请求映射用HashMap。Glide 内部有更复杂分层缓存,思路同源。sizeOf返回什么?
条目权重,Bitmap 缓存常返回像素字节数。线程安全吗?
LruCache本身非线程安全,多线程需外部同步或每线程实例。
#17 深拷贝和浅拷贝的区别? ⭐
标准回答
浅拷贝共享引用字段;深拷贝递归复制引用对象。Object.clone()默认浅拷贝。
面试官可能继续追问
Android 里深/浅拷贝注意什么?
传递可变List或Bitmap配置时,浅拷贝可能导致一处修改处处可见;需要隔离时用拷贝构造、copy数据类,或不可变集合。序列化算深拷贝吗?
通过字节流重建对象,通常算深拷贝但性能差,注意Parcelable仍要设计字段。Kotlin
data class copy?
浅拷贝按字段复制,引用字段仍共享。
#18 BIO 和 NIO 在 Android 网络中的视角? ⭐
标准回答
BIO 阻塞 IO,一线程一连;NIO 多路复用,少量线程管多连接。OkHttp 早期基于阻塞 IO + 线程池;底层仍可见 socket 阻塞语义,上层用连接池与 Dispatcher 复用线程。
面试官可能继续追问
Android 网络里 BIO/NIO 怎么理解?
应用层优先 OkHttp/Retrofit,不必手写 NIO,但要理解「阻塞调用别放主线程」。为什么 NetworkOnMainThreadException?
StrictMode 禁止主线程阻塞网络 IO。OkHttp Dispatcher 做什么?
限制并发请求数,复用线程执行Runnable。
#19 Java 8 lambda 在 Android 中如何工作? 💡
标准回答
源码是 lambda,DEX 编译经 desugar 转为匿名类或 invokedynamic 兼容实现,取决于 AGP 版本。
面试官可能继续追问
Android 里 Java 8 lambda 怎么用?
点击监听、Stream(API 24+ desugar)都依赖此机制。注意 lambda 捕获外部变量会形成合成类,不当持有Activity会泄漏。和 Kotlin lambda 比?
Kotlin 默认更轻量,但捕获this同样有泄漏风险。能直接上 Java 17 语法吗?
看compileOptions与 desugar 支持,AGP 8+ 支持更广。
#20try-with-resources和AutoCloseable是什么? 💡
标准回答
Java 7+ 语法糖:在try括号内声明AutoCloseable资源,块结束自动close(),异常时先抑制关闭异常再抛主异常。
面试官可能继续追问
Android 里
try-with-resources怎么用?
读InputStream、数据库Cursor、文件流应优先使用;Kotlin 对应use {}。避免手动finally漏关导致文件描述符泄漏。close抛异常怎么办?try-with-resources会 addSuppressed 保留两个异常信息。哪些 Android API 实现了
AutoCloseable?ParcelFileDescriptor、Cursor等,用完即关。
#21 Java 是值传递还是引用传递? 💡
标准回答
永远是值传递。传基本类型传值副本;传对象传的是引用的副本(地址值),通过副本仍可修改堆上同一对象,但不能让调用方变量的引用指向新对象。
面试官可能继续追问
Android 里值传递常见坑?
方法内list.add()有效,但list = new ArrayList()不影响外部引用——面试高频考点。为什么很多人说是引用传递?
把「传对象引用」口语化成引用传递,严格语义是传引用值的副本。Kotlin 一样吗?
一样,JVM 上语义相同。
#22 Java 8Stream在 Android 里能用吗? 💡
标准回答
部分 API 需 AGP desugar 且minSdk配合,小数据转换可用;列表很大或主线程路径慎用,因中间操作产生装箱与临时对象。
面试官可能继续追问
Android 里
Stream能用吗?
小数据转换可用;列表很大或主线程路径慎用。列表处理更常见for循环或 Kotlin 集合 API,不在 UI 热路径滥用。并行
parallelStream能在 Android 用吗?
一般不推荐,共享ForkJoinPool与 UI 线程竞争难控。和 Kotlin 序列比?
KotlinSequence惰性求值,更适合链式处理大数据。
面试策略速查
| 面试等级 | 建议掌握 |
|---|---|
| 初级 | ★★★☆☆ |
| 中级 | ★★★★☆ |
| 高级 | ★★★★★ |
必背知识(🔥)
==/equals/hashCode三连;ArrayListvsLinkedList;HashMapput/get、扩容树化;SparseArray/LruCache选型;final/异常体系。
高频追问
HashMap 为何容量 2 的幂;值传递 vs 引用传递;非静态内部类为何易泄漏;try-with-resources关闭顺序。
加分项(💡)
lambda desugar;深/浅拷贝;BIO/NIO 与 OkHttp;Java 8 Stream 在 Android 的边界。
容易踩坑
重写equals忘hashCode;static持 Activity;主线程网络/大列表;HashMap多线程写;final List误以为内容不可变。
完整链路一句通
Java 基础在 Android 里的主线:用正确的相等语义与hashCode驱动HashMap/LruCache/SparseArray选型 → 掌握final、异常、内部类与值传递等 OOP 规则 → 资源用try-with-resources关闭 → 网络与拼接遵守「阻塞不放主线程、少在热路径分配」。
相关推荐
Android 16(API Level 36)Activity 启动流程源码级解析
Android 高级工程师面试参考答案:性能优化
