1. 笔试整体概况与考察方向
1.1 这场笔试到底考什么
先聊聊我参加网易2020校招Android开发工程师(正式批)笔试的感受。说实话,当时看到“正式批”三个字,压力还是有的,因为这意味着难度和题量都会比提前批更规范、更接近实际工作能力要求。整场笔试大概是两个多小时,题量不算小,涵盖的知识面很宽,并不是单纯刷LeetCode就能应付的那种。
从题目结构来看,大致分成了几类:第一部分是单选题和多选题,主要考察Java基础、Android基础、计算机网络、操作系统常识;第二部分是编程题,一般是两道到三道算法题,难度在中等到偏上;第三部分则是简答题或设计题,会给你一个具体的场景,比如“如何设计一个图片加载库”或者“说说Handler机制的原理”,让你用文字表达思路。
很多同学容易犯的错误是只刷算法题,忽略了Android基础知识的深度理解。但网易的笔试很看重你对系统机制的理解深度,不是背概念就行,而是要能讲清楚“为什么”。比如考Binder的时候,不会只问“Binder是什么”,可能会问“为什么Android要选择Binder而不是共享内存”,这种题就需要你真正读过相关源码或至少理解底层的设计取舍。
1.2 岗位要求与笔试侧重点的对应关系
作为Android开发工程师,笔试侧重点很明确:语言基础(Java/Kotlin)、Android框架、数据结构与算法、网络与操作系统基础,再加上一部分实际工程中会遇到的性能优化和适配问题。
网易作为老牌互联网公司,它的Android开发岗位对基本功的要求非常高。我个人的体会是,笔试题目不会太偏门,但会在常见知识点上挖得很深。比如线程和进程的区别,大家都背过,但笔试可能会问“在Android中多进程会造成哪些问题?如何解决?”这就要结合ContentProvider、Application的多次创建等知识来回答。
另外,正式批还有一个特点:会涉及一些简单的Android Studio和Gradle相关的情境题。比如给你一段Gradle配置,让你判断哪里写错了,或者让你说说如何解决依赖冲突。这提醒我们,平时不能只盯着IDE的图形界面点来点去,要真正理解构建脚本背后的逻辑。
2. 核心考点拆解:Java与Android基础
2.1 Java基础:不只是背概念
Java是Android开发的基石,笔试中Java的占比通常能达到30%以上。我当时遇到的题里,集合框架、并发编程、JVM内存模型都考到了。
集合框架的重点不在“有哪些接口”,而在“底层实现和适用场景”。比如HashMap在JDK 7和JDK 8之间的变化、为什么容量要取2的幂次方、什么时候会触发红黑树化,这些都是高频考点。建议准备时顺着源码走一遍,画出put和get的流程图,比死记硬背强很多。
并发方面,synchronized和ReentrantLock的区别几乎是必考,但网易的风格是喜欢让你写一段可能出现死锁的代码,或者问如何用CAS实现一个计数器。这要求你对线程安全的理解不能停留在概念层,而是要真能写出无锁代码。
JVM内存模型部分,重点在于Java内存区域划分和GC机制。有一道题我记得很清晰:给出几段代码,判断哪些对象会在Young GC中存活多少回合,哪些会进入老年代。这种题看似简单,实际涉及对象晋升规则、大对象直接进入老年代、动态年龄判断等多个细节,非常考基本功。
2.2 Activity与四大组件:明白生命周期和启动模式
Android基础部分的考察,Activity绝对是重中之重。网易的笔试不喜欢直接问“Activity有哪几个生命周期方法”,而是会问“当A启动B,B是透明主题时,A的生命周期会怎样变化”。这种题就是考你是否真的理解onPause和onStop的触发时机,而不是死记硬背那张经典图。
启动模式同样是常客,但不会简单问“standard、singleTop、singleTask、singleInstance的区别”,而是结合具体场景,比如“有一个应用主界面是singleTask,从应用外部分享一张图片到这个界面,会走onNewIntent,如何保证界面收到最新的数据”。这种题我建议总结成一张表,分别列出启动模式、栈内行为、IntentFlags的优先级,再配合几个典型场景来记忆。
Service和ContentProvider也是重点。Service方面会考绑定服务和启动服务的关系、IntentService的实现原理、如何在Service中执行耗时任务;ContentProvider则会考它的作用、为什么它可以跨进程共享数据、和SQLite的关系等。此外,广播的静态注册在Android 8.0之后被限制,这也是考点之一,需要重点关注版本差异。
2.3 Handler与消息队列:真的理解Looper吗
Handler机制在Android面试中的出现频率极高,笔试也不例外。考察方式已经从“请简述Handler原理”升级为“有两个Handler,分别属于两个线程,如何实现线程间通信”,或者是“主线程Looper的loop()为什么不会导致ANR”。
要回答好这类问题,建议从这几个层面准备:第一,Handler、Looper、MessageQueue三者之间的关系;第二,ThreadLocal是如何保证每个线程只有一个Looper的;第三,MessageQueue的阻塞唤醒机制,为什么用epoll而不是普通的wait/notify;第四,同步屏障和异步消息的作用,这个相对冷门,但能说出来绝对是加分项。
我当时还遇到一道题,问“Handler.postDelayed之后,如果消息队列中有同步屏障,这个延迟消息会怎样”。这就很深入了,如果没有理解同步消息和异步消息的区分,很容易答错。建议大家去读一读MessageQueue和Message类的源码,把post、next、enqueueMessage这几个关键方法弄明白。
3. 高频算法与数据结构真题复盘
3.1 笔试常见的算法题型
网易的算法题和很多大厂一样,集中在数组、字符串、链表、二叉树、动态规划这几类,但考察方式比较灵活。比如不会直接让你“反转链表”,而是让你“反转链表的一部分”,或者“每K个节点一组反转”。这类题源自LeetCode,但会做变形,需要你真正掌握解题思想。
另外,TopK问题、滑动窗口、前缀和、并查集也是常客。我印象里有一道题是“给定一个正整数数组,找最长的子数组,使得子数组的和能被K整除”。这题用朴素O(n^2)会超时,必须用前缀和加哈希表优化,而且要注意同余定理。这种题不仅是考算法,也考你对时间复杂度的敏感度。
还有一个值得注意的点:笔试环境里题目输入输出需要自己写Scanner和System.out,很多刷题的同学平时用的都是核心代码模式,这一下就会慌。平时刷题时一定要多用ACM模式的在线OJ练一练,尤其是熟悉如何处理多组输入、怎样读入一行包含多个整数的字符串。
3.2 编程题的踩坑实录与解题思路
编程题我踩过不少坑,分享几个比较典型的。第一个坑是没注意数据范围,比如题目说数组长度是10^5,元素范围是10^9,那数组之和可能超过int范围,要用long,否则结果全错。这个属于低级错误,但考试时因为紧张很容易忽略,所以拿到题第一时间看数据范围,把类型定好。
第二个坑是题目给出了“答案可能很大,请对10^9+7取模”,很多人会在输出前统一取模,但如果在中间计算过程中就已经溢出了,那结果就不对。正确的做法是要在每次加法和乘法后都取模,养成习惯。
第三个坑是图论题目的输入格式。有些题目给的边不是从0开始编号,而是从1开始,那么数组初始化大小时就要多开一个位置。另外,如果题目没有说图是联通的,你需要考虑多个连通分量的情况,否则遍历会漏。
解题思路上,我建议按照“暴力-思考优化-实现”的顺序来。不是说你上来就写暴力,而是先用暴力思路确认自己读懂了题目,然后再往二分、双指针、动态规划等方向靠近。网易的算法题一般不会特别难,但只要能用最优解的题目,用暴力解大概率会超时,所以复杂度优化是必须的。
3.3 动态规划题的高频套路
动态规划在Android校招笔试里几乎是必考,但网易的DP题不会出特别变态的状压或树形DP,更多是常规的线性DP、背包问题、区间DP。
我当时遇到一道很经典的“编辑距离”变种题:给定两个字符串,允许插入、删除、替换,但是三种操作的代价不同,求最小代价。如果你只背过标准编辑距离,看到代价不同就会懵。这时候需要把状态转移方程改一下:dp[i][j]表示将word1前i个字符转换成word2前j个字符的最小代价,转移时如果是插入代价,就是dp[i][j-1]+insertCost;删除是dp[i-1][j]+deleteCost;替换是dp[i-1][j-1]+replaceCost(如果字符相同则不加)。想清楚这个,代码就很好写。
还有一类高频题是“从左上角到右下角的路径计数/最大路径和”,可以很容易地用二维DP解决。需要注意的是一些变体增加了障碍物,此时要格外小心初始化过程,如果第一行或第一列中间有障碍物,后面的格子都不可达。
4. 工具链与工程细节:从Gradle到性能优化
4.1 构建工具与Android Studio相关考点
网易笔试里出现过一个让我意外的模块——Gradle和Android Studio的基本使用。当时有一道选择题是关于AGP版本和Gradle版本兼容关系的,下面列出了几个AGP版本号,让你选哪个搭配是合法的。这要靠平时多看官方文档的版本对应表,不能只靠猜。
还有一道题是给了一段build.gradle片段,问你里面的依赖声明格式哪里有问题。比如implementation、api、compileOnly的区别,还有传递依赖导致的冲突。这个问题在真实工作中经常遇到,笔试考出来也反映了他们对候选人工程能力的重视。
除此之外,可能还会问Android Studio中如何查看方法调用堆栈、如何用Profiler分析内存泄漏、Logcat中如何过滤指定进程的日志等。这些都是日常开发中用得到的东西,如果你平时只会用“Run”按钮,遇到这些题就会露馅。建议大家日常开发时多留意IDE的细节功能,比如在Android Studio中可以通过“Show History”查看本地文件的历史版本,这在写代码时非常实用。
4.2 性能优化与内存泄漏
Android工程能力的另一个考察点是性能优化,笔试中会以简答题或案例分析的形式出现。比如会给你一段代码,问它为什么会造成内存泄漏,如何修改。典型就是匿名内部类持有外部Activity引用,导致Activity无法被回收。这个知识点不能只停留在“内部类会持有外部类引用”这句话上,要能说明GC Roots在哪,为什么静态变量会持有Activity。
还有关于图片加载的题,会给你一张大图,问怎么避免OOM。最优解是使用BitmapFactory.Options的inSampleSize进行采样,还要根据ImageView的尺寸计算出合适的采样率。更深入一点的话,可以提到复用Bitmap的内存(inBitmap属性)和Glide/Fresco的缓存机制。
对于ListView或RecyclerView的性能优化,笔试喜欢考convertView复用、ViewHolder模式、减少findViewById调用。如果是RecyclerView,还会涉及DiffUtil的使用、如何避免notifyDataSetChanged带来的全量刷新开销。这些知识点如果你有实际项目经验,回答起来会非常顺手,所以在准备笔试时不要只看书,一定要把平时写的代码串起来想。
4.3 多进程、序列化与跨进程通信
Android中跨进程通信是一个高频考点,因为它直接关联到实际项目的架构。笔试会问:为什么Android不建议在应用内频繁使用多进程?如何优雅地实现跨进程通信?
答案的核心在于多进程会带来几个问题:Application会被多次创建、静态变量和单例失效、SharedPreferences线程安全变成伪命题、四大组件需要在不同进程间传递数据时要使用Binder。对于进程间的数据共享,ContentProvider就是Android官方推荐的方式,因为它封装了Binder和跨进程数据传递的细节,而且有生命周期管理。
序列化方面,Serializable和Parcelable的区别也几乎是送分题。但网易会进一步问:在Intent中传递一个对象,如果这个对象的类被修改了,会发生什么?这涉及到serialVersionUID的问题,也提醒我们在实际项目中使用Serializable时要显式声明serialVersionUID,不然以后类结构一改,反序列化直接崩。
5. 网络、系统与适配:容易被忽略的考点
5.1 计算机网络基础:从TCP到HTTP
虽然是Android岗,但计算机网络也是笔试的常客。TCP三次握手、四次挥手、为什么TIME_WAIT要等2MSL,这些基础题希望你不会丢分。但网易的笔试可能会问得更实际,比如“如何优化弱网下的请求成功率”,答案是合理设置超时时间、使用重试机制、使用HTTP/2的多路复用、对数据进行压缩等。
HTTP和HTTPS的区别、HTTP/1.1与HTTP/2的区别、对称加密与非对称加密的配合方式,也都需要掌握。尤其是HTTPS的握手过程,最好能完整画出来:客户端发ClientHello,服务端回ServerHello+证书,客户端验证证书并生成预主密钥,用服务端公钥加密发给服务端,双方生成会话密钥开始加密通信。
Android开发还常考到网络库的选型,OkHttp、Retrofit、Volley的优缺点。笔试的简答题里,如果让你设计一个网络请求框架,记得要考虑到网络切换时的重试机制、请求取消、数据格式的自动解析、缓存策略、Cookie同步等问题。从工程角度去思考,这些都能体现你的项目思维。
5.2 Android权限、适配与OTA升级
随着Android版本不断更新,权限和适配问题越来越重要。笔试中可能会问:运行时权限机制是什么?如何申请多个权限?为什么Android 6.0之后要引入运行时权限?你需要回答从Android 6.0开始,危险权限需要动态申请,系统弹窗会打断用户操作,因此最好一次性申请一组相关权限而不是逐个申请。
Android 8.0之后的通知渠道(Notification Channel)、后台执行限制、隐式广播限制,Android 9.0的明文流量限制,Android 10的分区存储,Android 11的包可见性,Android 12的精确闹钟权限,Android 13的通知权限,Android 14的前台服务类型要求……这些版本差异如果没做过适配,确实很难记住。建议做一张版本特性大表,把每个版本对应的行为变更和适配策略写清楚。
OTA是另一个容易被忽略的考点,但网易笔试居然考了。它问的是Android OTA升级的基本流程和增量升级的原理。OTA升级可以由系统服务收到升级包后,写入到特定分区,然后在重启时通过Recovery模式进行升级。增量升级使用差分算法生成patch包,减少下载流量。虽然这个问题偏系统,但作为Android开发,了解一些系统级的机制会让你在面试中更加分。
6. 笔试现场经验与备考建议
6.1 时间分配与答题顺序
不同人有不同的答题习惯,但针对网易这场笔试,我建议这样分配时间:单选多选和基础题控制在40分钟左右,编程题每道留20-25分钟,剩下时间留给简答题和检查。如果某道题卡住了,不要死磕,直接标记跳过去,先把能拿的分拿到。
在编程题中,可以先写一个暴力解,确保能通过一部分用例,然后再优化。因为校招笔试的评测用例通常分梯度,暴力解能拿到30%-50%的分数,总比交白卷强。但要注意,如果你暴力解通过了一部分用例,后来又写出了最优解,要确保最终的提交代码是优化后的版本,不要因为紧张提交了旧的代码。
另外,笔试环境一般支持本地IDE和在线编译的切换。我建议先用本地IDE调试,因为代码提示和报错信息比较直观,但最后一定要把代码复制到在线提交框里,并且检查一下有没有多余的调试输出,否则会WA。
6.2 考前一周如何冲刺
考前一天不要做新题了,重点复盘自己的错题和笔记。可以把Java集合的源码结构、Handler机制、Activity生命周期、常见算法模板(二分、快速排序、并查集、滑动窗口)在纸上默写一遍,加深印象。
如果时间充裕,刷题时尽量按专题来,比如今天只做二叉树,明天只做动态规划,这样能快速形成套路。但真题模拟也很重要,可以找一个安静的环境,按真实考试时间做一套模拟题,提前感受下节奏。
还有一个容易被忽视的点:面试笔试前一定要确保Android Studio和本地环境正常,但笔试时经常需要自己在网页上写代码,IDE依赖较少。不过某些简答题可能会让你贴代码,这时候代码格式清晰很重要,写缩进、命名都要规范。网易的判卷有机器也有真人,一份清晰工整的代码观感会好很多。
6.3 心态调整与细节检查
笔试现场最大的敌人是心态。我见过很多人因为一道题没做出来,后面整个节奏全乱了。建议在笔试前深呼吸,告诉自己“不会的题别人也不会”,把注意力放在能拿到的分数上。
交卷前一定要检查这些细节:编程题的文件名和类名是否符合要求,是否引入了正确的包,变量名是否冲突,输入输出是否和题目要求的格式完全一致,比如“每行输出一个整数”和“每个整数用空格隔开”,一字之差就可能导致零分。
还有一个很实用的技巧:在写算法题时,可以在代码里加注释,写清楚每一段思路。这样即便代码有bug,阅卷人看到你的思考方向正确,也可能给一些步骤分。当然,不要写无关的注释,那种“这里调用了一个很神奇的方法”之类的注释没有任何意义。
6.4 网易2020正式批笔试给我的最大启发
考完这场笔试之后,我最深的感受是:大厂校招笔试不仅仅是一次知识测试,更像是一次工程素养的预检。它不会问特别深奥的源码细节,但会把多个知识点串联起来,考察你是否能把零散的Android知识整合成体系。
举个例子,单纯问“Activity启动流程是什么”,大部分人能答上来一点;但给你几个类名,让你排出它们的调用顺序,并且说明其中涉及哪些关键方法,这就难不少。我在备考过程中,自己画了一张Android系统启动和Activity启动的流程图,每看一次源码都往上面补充一点细节,最后笔试时遇到相关题目答得很顺畅。
建议每位准备Android校招的同学都建立一份属于自己的知识图谱,不要只是收藏别人的面试题,要自己写答案。写一遍和看一遍的记忆效果完全不同。我当时把Handler机制、Binder机制、ClassLoader机制都自己讲了一遍,还用手机录下来回听,很快就发现了自己理解得模糊的地方,然后再去查资料修正。
最后再分享一个小技巧:在复习时一定要关注Android官方文档和Android开发者博客上的最新内容,尤其是每一年的大版本更新。网易的笔试题目虽然不会直接用最新的API考你,但知识点背后的设计思想往往是相通的。理解“为什么这样设计”,比记住“它是什么”更能帮助你在笔试中脱颖而出。