十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

金山办公2020校招Android笔试真题解析:考点与答题思路

金山办公2020校招Android笔试真题解析:考点与答题思路 又到校招季很多朋友在找Android开发方向的笔试真题。金山办公2020校招Android开发工程师笔试题二这套卷子我当年刷的时候印象挺深后来给团队出面试题时也参考了它的思路。这套题不是那种死记硬背的八股合集而是把Java基础、Android核心机制、性能优化、甚至工程化问题揉在一起考很能反映一家做办公软件的公司对候选人的真实要求。这篇内容我就以这套题为引子把高频考点、答题思路、背后原理都拆开讲一遍不管是准备校招还是社招跳槽都能直接用上。1. 这套笔试题到底在考什么1.1 从一份笔试题看企业选人逻辑先明确一个前提笔试不是看你背了多少面试题而是看你在没有IDE、没有网络、有限时间的前提下能不能调用知识体系解决问题。金山办公的主打产品是WPS这类办公App对稳定性、流畅度、兼容性的要求极高所以考点会明显偏向Java并发、Android消息机制、进程通信、性能优化和代码设计。我拿到的这套二卷子整体难度在同级别公司里算中上。选择题部分覆盖了Java内存模型、集合类、多线程、Activity启动模式、Handler机制、网络协议等。简答题里出现了Activity A启动Activity B时生命周期如何变化Handler导致内存泄漏的原因及解决方案。代码题则是一道手写LRU缓存和一道自定义View测量逻辑。怎么看都不是靠短期背题能应付的需要真正理解原理并且有手写代码的功底。1.2 试卷结构和题型分布从题型结构上我复原一个大致的框架不同批次可能微调题型数量侧重点单选题10道左右Java语法、Android基础、网络协议、数据结构多选题5道左右边界情况、易混淆概念、多知识点交叉简答题3道左右源码分析、机制原理、方案设计编程题1-2道数据结构与算法、自定义View、线程交互单选的很多题是下列哪个说法正确或下列哪个方法在onCreate中不被调用这类考得很细。多选题最容易失分因为选项之间往往只差一个限定词比如关于Handler的说法正确的有里面把同步屏障和IdleHandler混在一起。这些如果平时只是用API不看源码基本会错一半。编程题的时间分配很关键建议60分钟左右的笔试给编程题留25到30分钟。如果前面选择题卡太久后面代码题写不完反而得不偿失。2. 高频考点逐个拆解2.1 Java基础与并发不只是背概念Java基础在笔试题里占的比重大概三分之一但考察的深度经常会超出预期。String那类问题几乎每套题都有比如String和StringBuilder的区别和equals的区别。如果只答String不可变、StringBuilder可变最多拿一半分。更好的答法是String底层final char数组Java 9之后是byte数组每次修改都产生新对象循环拼接会频繁GC。StringBuilder和StringBuffer都继承AbstractStringBuilder区别是StringBuffer的append方法加了synchronized单线程下优先用StringBuilder。用a b这类字面量拼接编译器会自动优化成StringBuilder但循环内拼接每次都会new StringBuilder。另一个重头戏是线程池。笔试题常给出一个Executors.newFixedThreadPool(3)问核心线程数、最大线程数、队列长度分别是多少以及会不会OOM。这就要说清楚ThreadPoolExecutor的7个参数corePoolSize、maximumPoolSize、keepAliveTime、TimeUnit、BlockingQueue、ThreadFactory、RejectedExecutionHandler。Executors.newFixedThreadPool底层用的是LinkedBlockingQueue队列默认Integer.MAX_VALUE任务排长队时会占大量内存所以企业规范里往往不让直接用Executors要手动new ThreadPoolExecutor用有界队列和显式拒绝策略。并发里还有个高频题双重检查锁单例为什么要加volatile。笔试题会问这段代码是否有问题如果不加volatile第二个线程可能在instance还没初始化完成时就拿到引用原因是CPU指令重排导致new Singleton()的三步操作分配内存、初始化对象、赋值引用不保证有序。volatile禁止重排这个问题才解决。2.2 Android四大组件深挖四大组件里Activity和Service是考察重点。Activity的启动模式和Intent Flag组合几乎每份卷子都会出现。standard、singleTop、singleTask、singleInstance四种模式要背但更重要的是理解实际场景。比如WPS从文档页跳转到分享页如果用singleTop当前Activity在栈顶时复用onNewIntent而不会新建如果用singleTask会清掉该Activity之上的所有Activity。Service的考察点在两种启动方式。startService和bindService的区别不只是生命周期面试官常追问bindService方式下onUnbind返回true后再次bind会不会调用onRebind答案会。还有进程通信AIDL的流程Messenger和AIDL的对比。这些在纯笔试里可能只出判断题但后面面试会连环问。BroadcastReceiver动态注册与静态注册的区别也很经典。Android 8.0之后静态注册绝大多数隐式广播都不能在AndroidManifest里接收了所以有些老项目检查一遍把不必要的静态注册改成动态。ContentProvider考得相对少但WPS这种应用内容提供者常用于文件访问和跨进程数据共享题目可能会问ContentProvider的onCreate调用时机Application.attachBaseContext之后Application.onCreate之前。2.3 Handler与消息循环必考源码题几乎每一套Android校招笔试题都绕不开Handler。常见问法包括Handler、Looper、MessageQueue三者关系。一个线程有几个Looper几个Handler主线程的Looper在哪创建子线程里如何new Handler必须先调用Looper.prepare()再调用Looper.loop()。Handler的post()和sendMessage()有什么区别源码上看post最终也是调用sendMessageDelayed把runnable包装成messagecallback为runnable。MessageQueue.next()中如果队列为空会阻塞为什么不会导致主线程卡死因为主线程在loop()里无限循环有消息就执行没消息就阻塞等待而各种callback会往队列里放消息。再往深处问还有同步屏障、消息优先级、IdleHandler。笔试中加入IdleHandler往往作为加分项比如Activity的onResume之后通过IdleHandler做懒加载是一个不错的实践。如果答不上来前面答对了也不至于挂但如果能答上来基本就能和别的候选人拉开差距。关于内存泄漏的答案最好按这个层次来非静态内部类Handler默认持有外部Activity引用 - 消息队列中如果有延迟消息会一直持有Handler - 导致Activity无法回收。解决思路有静态内部类 WeakReference或在onDestroy时removeCallbacksAndMessages(null)。如果用一个全局单例的Handler其实不存在内存泄漏问题但要注意线程安全。2.4 性能优化与内存管理办公App和社交App不一样用户会在手机上打开几十MB的文档滑动、缩放、渲染、保存任何一步卡顿都非常明显。所以金山这类公司特别爱考性能优化。笔试题常见的有内存泄漏的常见场景静态变量引用Activity、Handler、非静态内部类持有外部类、匿名AsyncTask持有Activity、单例里持有Context。需要区分ApplicationContext和ActivityContext。可以用LeakCanary检测内存泄漏原理是监控Activity.onDestroy之后通过ObjectWatcher在Activity被Gc之前保存引用如果等待一段时间后还是没被回收就Dump Heap分析引用链。布局优化include、merge、ViewStub的使用场景。合理使用ConstraintLayout减少嵌套。如果笔试出布局代码让你看哪里可以优化通常能发现RelativeLayout嵌套多层LinearLayout的问题。过度绘制、卡顿优化、Traceview和systrace的使用虽然不一定让你写但简答题里可能会让你设计一个应用启动优化方案。关于启动优化常见思路是在Application中只初始化必须的库把业务初始化延时或放到子线程使用ContentProvider自动初始化但注意时序用启动加速框架比如AnchorTask形成任务依赖图还有今天启动页秒开、减少dex加载耗时等。答题时至少要写出分层初始化异步化时序清晰这符合工程思路。2.5 网络与数据存储网络这一块笔试题不会让你直接写HTTP报文但会问HTTPS的加密过程OkHttp的拦截器链以及TCP和UDP区别。尤其是TLS握手过程是很多公司的必考题。需要能说出客户端发送ClientHello服务端返回证书客户端验证证书并生成随机密钥并用公钥加密服务端使用私钥解密得到对称密钥之后双方用对称加密通信。要分清公钥加密和对称加密的区别。数据存储方面SharedPreferences是老考点。会问多次commit和apply有什么区别。commit同步返回booleanapply异步并且不返回结果apply过程中如果Activity在onPause之后由ActivityThread中的QueuedWork等待写入完成可能导致ANR。所以如果频繁小数据写入且能容忍丢失用apply需要立即生效且关心结果用commit。进阶点是MMKV基于mmap的文件映射写入时直接写到内存并由系统回调刷盘性能远好于XML序列化。网络题目中还经常出现如何设计一个可扩展的拦截器链这其实就是OkHttp的设计。如果能把Chain理解为链表每个Interceptor拿到Request和Chain处理后调用chain.proceed继续传递笔试分就拿到了。2.6 手写代码题与算法思路代码题虽然只有一两道但含金量最高。我见到最多的两类是手写LRU缓存、模拟一个生命周期相关的逻辑。一道典型的LRU题实现一个LRUCache要求get和put的时间复杂度O(1)。标准解法是双向链表HashMap达到容量上限时删除链表尾部节点新访问的节点移到头部。很多人能背出LinkedHashMap的removeEldestEntry但笔试要求手写平时不看链表操作的人容易卡住。写的时候注意几个细节定义双向链表节点NodeK,V。HashMap用于查找节点每个节点需要同时保存key和value因为删除尾部节点时要拿到key去map里删除。包含虚拟头尾节点翻转操作时避免空指针。头尾节点初始化时互相连接moveToHead和removeNode要逻辑统一。手写完成后再答一道追问如果并发读写怎么办此时想到加锁或者用读写锁或者直接同步代码块。这考察工程意识。还有一种代码题是分析View的测量和布局给出一个自定义View的onMeasure问你measure mode是AT_MOST时应该怎么做。此时需要明确区分EXACTLY、AT_MOST、UNSPECIFIED三种情况并且说明MeasureSpec是父View限制子View的规则。常见错误是直接使用getDefaultSize而不根据mode判断导致wrap_content时占满全屏。3. 复盘一次真实笔试过程3.1 考前准备清单讲完知识点我再用实际经验说说怎么准备这套题。如果你正在准备Android校招下面这份清单可以照着复习Java基础集合源码、HashMap原理、并发包、异常、泛型、注解。数据结构链表、栈、队列、二叉树、HashMap、LRU、TopK。Android核心Activity生命周期与启动模式、Fragment生命周期、Service、BroadcastReceiver、ContentProvider。消息机制Handler、Looper、MessageQueue、Choreographer、IdleHandler。事件体系事件分发、手势冲突、多点触控。性能优化内存泄漏、布局优化、卡顿、APK瘦身、功耗。网络HTTP/HTTPS、TCP/IP、OkHttp、Retrofit、JSON。项目亮点梳理项目里最复杂的一个技术点能用两句话说清楚遇到什么问题-怎么解决的-结果怎么样。注意简历上写的任何一个熟悉都可能被面试官拎出来细问。写熟悉Handler机制就要准备好被问到native层。写熟悉内存优化就要准备LeakCanary源码。所以准备笔试答案的同时也要把面试追问准备好。3.2 答题时间分配与策略正常笔试的做题节奏我是这么安排的前5分钟先通读全卷标注出哪些题是拿分题、哪些题是难点。选择题控制在25分钟内不确定的先标出来不要恋战。有5道单选、3道多选、2道简答、1道代码题的卷子整体时间60分钟这样时间基本够用。简答题每题8到10分钟先写结论再写理由再补充细节。比如为什么Handler会导致内存泄漏这类题答案写会之后要快速展开现象、原因、解决方案分点写清楚。千万不要只写不会或会而没有论述阅卷人会默认你只是猜的。编程题留最后25到30分钟。如果时间不够先写思路和数据结构再写核心逻辑最后补边界判断。最忌讳上来就默写代码然后发现思路错了整段推倒。3.3 手写代码题的典型踩坑手写代码的时候因为不是在IDE里很多程序员会暴露出基本功短板。常见问题有几个第一不判空。比如输入数组可能为null链表可能为null有些人上手就写length访问在笔试这种环境里很容易被扣分。第二循环边界搞错。LRU删除节点时忘了处理头尾节点或者HashMap的key和value类型不一致。写完之后如果时间充裕一定要用几组样例在草稿纸上模拟一遍。第三变量命名随意。定义temp、a、b阅卷人看着费劲也容易把自己绕晕。我建议用有意义的命名例如preNode、nextNode、newNode。第四不考虑扩容和并发。HashMap或LinkedHashMap写出来很简单但笔试要的是双向链表HashMap这是考点。如果写个LinkedHashMap虽然实现正确但没展示出你的数据结构功底可能就拿不到满分。4. 常见易错点与排查技巧实录4.1 最容易失分的5个知识点这几年的笔试以及简历筛选中我发现几个特别容易失分的地方整理成表格方便对照易错点错误理解正确理解onNewIntent认为singleTop启动模式下每次都调用onNewIntent只有目标Activity已在栈顶时才会调用onNewIntent不在栈顶时仍走onCreatedp与px认为dp就是物理尺寸单位dp是密度无关像素在mdpi密度下1dp1px在xhdpi下1dp2pxParcelable与Serializable认为Serializable性能更好Serializable使用反射序列化慢Android跨进程传输对象优先选ParcelableHandler.getMessage认为Message的obj和what必须同时存在what标识类型obj携带对象无必然绑定关系复用Message要清理字段Activity的启动模式组合只背四种模式要结合Intent Flag例如FLAG_ACTIVITY_NEW_TASK、FLAG_ACTIVITY_CLEAR_TOP等组合效果比如第4条因为面试官可能问消息池中的消息如果被发送出去之后要不要回收这其实就是Message.obtain()和recycle()的使用但很多人会答成发出去就不管了。正确做法是在Message使用完毕比如Carrier处理完后如果不再需要可以回收但Handler内部在分发完消息后并不自动回收而是由MessageQueue在next()中取出消息后设置字段并复用。如果某个消息设置了callback执行完不回收导致Message被MessagePool复用后字段残留就会踩坑。4.2 面试官追问环节如何应对笔试提交后通常还有一轮技术面围绕试卷展开。这时面试官不会单纯念答案而是在你的回答基础上深挖。我这里列举一些真实的追问方向你写了Handler内存泄漏解决方式面试官会问为什么要用WeakReference如果Activity还在正常使用不会是弱引用吗答案是弱引用会在GC时被回收但Handler发送延迟消息时如果持有Activity弱引用即使消息还没执行只要Activity没有被强引用它就可能被回收而Handler本身还在处理消息。但要注意Handler的Runnable或Callback如果持有Activity的强引用哪怕Handler是静态的泄漏依然存在。你写了LRU面试官会问如果只让你用get和put你会怎么改如果数据量很大用HashMap会不会内存不够这时可以提到可以在节点上增加访问时间戳也能实现但时间复杂度不是O(1)。还可以提能否用Redis的近似LRU思想但笔试一般不必讲这么深。简答题里写使用ViewStub优化布局面试官追问ViewStub和include都能复用布局什么时候用ViewStub答案是当某个布局不是必然显示时用ViewStub替换初始化开销include用于固定静态区域比如公共头部底部。4.3 关于这套题的一点个人体会在准备这套题的过程中我最大的感受是它不鼓励死记硬背而是要求知其然知其所以然。比如Activity启动模式光记住singleTop栈顶复用不够还要能描述出调用链。写代码题时不仅要能运行还要能解释复杂度。我后来把这套题的错题整理成了一个Notion笔记每道题都补了源码截图和实验数据效果比抱着一堆PDF资料好太多。如果你正在准备类似笔试建议你每天花两小时做三件事一是用源码视角读框架二是手写一遍核心数据结构三是自己出题考自己。比如看完Handler源码后合上电脑在白纸上画出Looper.loop()的执行流程和消息回收路径。画不出来的地方就是薄弱点。做两三套这种笔试题后你会发现考官的出题逻辑其实很清晰就是用一道题筛选出看过源码的人和只调过API的人。我最后再分享一个小技巧笔试时如果遇到不会的简答题不要留白。把相关的、确定正确的知识点写上去再说明遇到这个问题我会先通过xxx定位再在xxx处解决。这体现了解决问题的思路很多阅卷官会因此给你步骤分。笔试本身就是一场压力测试谁都会遇到盲区但能不能用逻辑和表达弥补盲区恰恰是公司想看到的能力。
返回列表