ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

京东Android校招笔试复盘:核心考点与备考指南

2026/8/31 20:42:45 拓冰建站 浏览量
京东Android校招笔试复盘:核心考点与备考指南 京东2019校招Android开发工程师笔试题我前前后后刷了三遍。第一遍当考试做第二遍逐题查漏补缺第三遍把每道题背后牵扯的知识点都整理成了专题。现在回头看这套题给我的收获远不止“通过笔试”这么简单——它几乎覆盖了Android开发日常工作中最常用的核心知识而且考察方式很“京东”重基础、重实战、不玩偏题怪题。坦白说现在很多校招笔试题越出越偏什么稀奇古怪的冷门API都往上堆但京东这套题风格不太一样。它考察的内容基本就是你在实际开发中每天都会碰到的东西Activity启动模式、Handler机制、View绘制流程、数据结构与算法、Java并发基础、网络协议……这些知识点不复杂但想答好需要你是真的理解而不是死记硬背。这也是我为什么想把这套题拿出来做深度复盘——它代表了大厂校招笔试的典型风格刷透一套比盲目刷十套都有用。如果你是正在准备Android校招的在校生或者刚入行想系统打一遍基础的初级工程师这篇文章值得你花点时间认真看。我会把每道题的考点、答题思路、容易踩的坑都拆开讲清楚同时补充一些当年面试官在后续面试环节追问过我的问题帮你建立一套完整的备考知识框架。提示文章涉及的是2019年京东校招Android方向的笔试题技术栈以当时的Android主流版本为基础但绝大多数底层原理如Handler、Binder、View绘制等至今未变对现在的校招备考依然有很强的参考价值。1. 从一套笔试题看京东Android校招的考察逻辑1.1 题目整体结构与考察范围分析京东2019校招Android开发工程师笔试题整体题量大概在40道左右考试时间90分钟题型以单选题、多选题和编程题为主部分场次还会加入简答题。从题目分布来看考察重点主要集中在以下几个模块Java基础与并发约占30%包括集合框架、异常处理、多线程与线程池、JVM内存模型等。Android核心机制约占35%包括Activity与Fragment、Service、Handler消息机制、Binder通信、四大组件等。数据结构与算法约占20%涉及数组、链表、二叉树、排序算法、动态规划等。计算机网络与操作系统约占10%以TCP/IP、HTTP协议为主。开放性题目约占5%比如项目经历、职业规划、遇到的最有挑战性的问题等。从这个比例能明显看出京东校招笔试最看重的是候选人的Android基础知识扎实程度。那会儿Android开发正处在从“会调用API”向“懂底层原理”转型的阶段面试官特别反感那种只会用第三方库、但不理解内部机制的候选人。1.2 “懂原理”和“会用API”的差距在哪里举个例子题目里考了Handler消息机制。如果只是背过“Handler用于子线程更新UI”那你最多能答对一道选择题。但如果题目换一种问法“Looper.loop()为什么不会阻塞主线程MessageQueue.next()在什么情况下会阻塞IdleHandler的执行时机是什么”这时候背答案的人就完全懵了。我当年复习Handler时也走过弯路一直停留在“会用”的层面直到被一道关于“Looper死循环为什么不会导致ANR”的题目难住才意识到自己根本没有真正理解Android的消息循环机制。后来我把MessageQueue的源码从头到尾读了两遍才彻底搞明白Looper.loop()的死循环并不占用CPU时间片——它在没有消息时会通过epoll机制进入休眠把CPU让出去等有消息写入时再被唤醒。这就是“懂原理”和“会用API”的本质区别。所以这篇复盘文章里我不仅会告诉你每道题选什么更重要的是帮你搞清楚背后的原理和逻辑。这样才能做到举一反三不管笔试题目怎么变核心答案始终跑不出你的知识框架。1.3 备考优先级这套题给你的复习排序建议刷完这套题我总结出一个非常清晰的复习优先级按这个顺序准备效率会高很多第一优先Java集合源码与并发编程。这是笔试出现频率最高、也最好拿分的部分。HashMap的底层实现、ConcurrentHashMap的锁机制、线程池的核心参数、synchronized和volatile的区别属于必背必懂的内容。第二优先Android四大组件与消息机制。Activity启动模式、任务栈、Fragment生命周期、Handler与Looper的关系、Binder通信原理这些是Android开发者的看家本领笔试几乎必考。第三优先View体系与性能优化。自定义View的测量和绘制流程、事件分发机制、内存泄漏的常见场景、ANR的成因和定位方法属于拉开分差的部分。第四优先数据结构与算法。校招笔试基本离不开算法题重点复习数组、链表、二叉树、栈与队列、排序算法和简单动态规划。京东的算法题难度中等不至于出特别偏的题目但基本的数据结构和经典题型必须熟练。第五优先网络协议。TCP三次握手、四次挥手、HTTP与HTTPS的区别、HTTP状态码的含义掌握这些基本够用。按照这个顺序复习可以保证先拿下基础分再冲击高分策略上比较稳妥。2. Java核心考点深度拆解这部分决定你的笔试下限2.1 HashMap与ConcurrentHashMap的底层实现京东笔试Java部分几乎必考HashMap。2019年那套题里有一道多选题考察HashMap在JDK 7和JDK 8中的差异涉及底层数据结构、插入方式、扩容机制等多个维度。JDK 7中的HashMap底层是数组加链表的结构插入元素使用头插法。并发情况下扩容可能形成环形链表导致死循环这个问题在面试中经常被追问。JDK 8中的HashMap底层改为数组加链表加红黑树的结构。当链表长度超过8且数组长度大于64时链表会转化为红黑树将查询时间复杂度从O(n)降到O(log n)。插入方式也改为尾插法从根源上解决了并发扩容死循环问题但并不意味着HashMap在并发环境下就是安全的。注意HashMap的容量始终是2的n次幂即使你在构造时传入的初始容量不是2的n次幂它也会帮你调整到最近的2的n次幂。这样设计的目的是让hash值计算下标时可以用(n - 1) hash来代替取模运算效率更高。ConcurrentHashMap也是高频考点。JDK 7中它使用Segment分段锁默认并发级别是16把整个Map分成16个Segment每个Segment独立加锁不同Segment之间可以并发操作。JDK 8则放弃了分段锁改为CAS加synchronized只锁链表或红黑树的头节点锁粒度更细并发性能更好。当时笔试有一道题就问JDK 8的ConcurrentHashMap在什么情况下会使用synchronized答案是当发生哈希冲突需要向链表或红黑树中插入节点时会对桶的头节点加锁。我建议复习这块时一定要亲手画一遍HashMap的put流程先算hash再寻址判断是否为空桶然后判断是链表还是红黑树再判断是否需要扩容最后判断是否转化为红黑树。把这个流程画熟了无论笔试怎么问都能应对。2.2 JVM内存模型与垃圾回收机制JVM相关问题在京东笔试中占比不算特别大但属于Java基础中的基础一般以选择题或判断题形式出现。常考的点有运行时数据区划分程序计数器、虚拟机栈、本地方法栈、堆、方法区JDK 8后改为元空间。其中栈是线程私有的堆是线程共享的。对象创建过程类加载检查、分配内存、初始化零值、设置对象头、执行构造方法。判断对象死亡的算法引用计数法和可达性分析算法。主流JVM用的是可达性分析从GC Roots出发向下搜索搜索不到的白色对象即视为可回收。垃圾收集算法标记-清除、标记-复制、标记-整理。新生代用复制算法老年代用标记-清除或标记-整理。类加载机制双亲委派模型Bootstrap ClassLoader、Extension ClassLoader、Application ClassLoader的层级关系。有个很容易出错的点方法区元空间会不会发生垃圾回收答案是会的。方法区主要回收两类东西废弃常量和无用的类。无用的类需要同时满足三个条件该类的所有实例都已被回收、加载该类的ClassLoader已被回收、该类的Class对象没有被任何地方引用。京东那套题里有一道判断题问“方法区不会被垃圾回收”答案是错误很多同学在这个点上栽了跟头。2.3 多线程基础与线程池的核心参数多线程在笔试中的重要性怎么强调都不过分。京东2019年的笔试题里有一道关于ThreadPoolExecutor核心参数的题考察的是corePoolSize、maximumPoolSize、workQueue和拒绝策略之间的关系。题目大概意思是当提交的任务数超过核心线程数且任务队列已满时线程池会如何应对答案是线程池会创建新线程来处理新任务直到线程数达到maximumPoolSize如果这时候还有任务提交就会触发拒绝策略。这里我必须强调一个容易搞混的顺序先判断核心线程数是否已满再判断任务队列是否已满最后判断最大线程数是否已满四个判断条件有严格的先后顺序。Java中线程池的处理流程是当提交一个新任务时如果当前运行的线程数少于corePoolSize则创建一个新线程来处理任务。如果当前运行的线程数大于或等于corePoolSize则将任务加入阻塞队列。如果队列已满且当前运行的线程数少于maximumPoolSize则创建非核心线程来处理任务。如果队列已满且当前运行的线程数已达到maximumPoolSize则执行拒绝策略。四种拒绝策略也要背清楚AbortPolicy直接抛出异常默认策略、CallerRunsPolicy用调用者所在线程执行任务、DiscardPolicy直接丢弃任务不抛异常、DiscardOldestPolicy丢弃队列中最老的任务然后重新提交。我当时复习线程池是从一个实际场景理解的一个外卖平台在下单高峰期大量订单任务涌入。系统先让固定数量的核心骑手corePoolSize处理订单订单太多时先排队workQueue队都排满了就临时加派骑手maximumPoolSize但还是处理不过来就只能拒绝新订单或者让用户稍后再试拒绝策略。这样类比下来线程池的参数就比较好记了。2.4 volatile与synchronized的区别及可见性原理Java并发编程中最经典的问题没有之一。京东笔试里考了一道单选题问volatile关键字保证了什么。选项包括原子性、可见性、有序性、持久性。正确答案是volatile保证了可见性和有序性但不保证原子性。可见性当一个线程修改了volatile变量的值新值会立即刷新到主内存中其他线程读取该变量时必须从主内存重新读取而不是使用本地内存中的缓存副本。有序性volatile通过内存屏障禁止指令重排序确保读写操作的顺序不会被JVM随意调整。不保证原子性比如volatile int count的count操作本质上是三步读取count的值、加1、写回count。这三步之间可能被其他线程打断所以结果可能不正确。关于synchronized需要记住它锁的是对象头中的Monitor监视器锁支持可重入在JDK 6之后引入了偏向锁、轻量级锁、重量级锁的升级过程。锁可以升级但不能降级这是JVM为了优化性能做的设计。我记得当时笔试有一道多选题问“下列哪些操作是原子的”选项里有i、i 1、i 1、i i 1。正确答案只有一个i 1因为引用赋值或基本类型赋值是原子操作。这个题考察的就是对volatile语义的理解——很多人选了i以为它是一步操作实际上它是读改写三步。3. Android核心机制专项解析笔试的重头戏3.1 Activity启动模式、任务栈与onNewIntentActivity这块属于笔试必考几乎没有例外。京东2019年笔试题里有一道关于启动模式的题“下列哪种启动模式适用于通知栏点击跳转页面的场景”答案应该是singleTop或singleTask具体要看场景。这里把四种启动模式完整梳理一遍同时补充各自的适用场景。standard标准模式每次启动Activity都会创建新的实例并压入启动它的那个任务栈。这是默认模式也是最简单的一种。适用场景普通页面跳转比如从列表页跳到详情页一般使用standard模式因为每次打开详情页都是全新的页面。singleTop栈顶复用模式如果目标Activity已经位于任务栈的栈顶则不会创建新实例而是复用栈顶实例并回调onNewIntent()。如果目标Activity不在栈顶则行为与standard相同会创建新实例。适用场景通知栏点击跳转、搜索结果页跳转等避免在栈顶重复创建同一个页面。比如你在阅读一篇新闻没退出又点了一次通知栏推送如果不设置singleTop就会在栈顶压入一个一模一样的页面用户按返回键还要再返回到原来的页面体验很差。singleTask栈内复用模式如果目标Activity在任务栈中已经存在实例则将该实例上面的所有Activity全部出栈销毁让目标Activity回到栈顶并回调onNewIntent()。如果目标Activity不存在则创建新实例。适用场景应用的主页、电商App的首页底部Tab、微信的主界面等。从浏览器点击链接跳转到App主界面如果App已经打开应该直接把主界面拉到栈顶而不是新开一个主界面。singleInstance单实例模式目标Activity独占一个全新的任务栈且该栈中只有这一个Activity实例。适用场景来电界面、闹钟界面、视频通话界面等需要全局唯一的界面。启动模式的设置方式有两种在AndroidManifest.xml中通过android:launchMode属性静态设置或者在代码中通过Intent.setFlags()动态设置。但需要注意静态设置和动态设置同时存在时动态设置的flag优先级更高会覆盖静态配置。onNewIntent()的调用时机也要记清楚当Activity被复用且通过onNewIntent()回调传递新Intent时系统会先调用onPause()、onNewIntent()、onResume()不会走onCreate()和onStart()。所以在新Intent中拿数据必须在onNewIntent()中重新处理而不能依赖onCreate()中的getIntent()。注意有一种非常隐蔽的情况是Intent.FLAG_ACTIVITY_CLEAR_TOP和singleTask组合使用。如果目标Activity是singleTask模式同时设置了FLAG_ACTIVITY_CLEAR_TOP系统会复用已有Activity并清空它上面的所有Activity。但如果在standard模式下使用FLAG_ACTIVITY_CLEAR_TOP系统会销毁目标Activity并重新创建新实例而不是复用旧实例。这个细节经常被拿来出多选题。3.2 Handler消息机制从ThreadLocal到epoll的完整链路Handler是Android笔试中的“必考题”也是拉开分数的关键题。京东的笔试题里Handler相关题目通常有两三道涉及Looper、MessageQueue、Handler、ThreadLocal四者的关系。核心概念Handler负责发送消息和处理消息。在主线程中创建Handler重写handleMessage()方法处理子线程发送过来的消息。Looper负责循环读取MessageQueue中的消息并分发到对应的Handler。一个线程只能有一个Looper通过Looper.prepare()和Looper.loop()来实现。MessageQueue消息队列内部是一个单链表结构按时间顺序排列消息。注意它不是阻塞队列而是通过native方法实现线程挂起和唤醒。ThreadLocal每个线程持有独立的Looper对象ThreadLocal保证每个线程访问到的是自己线程的Looper实例。完整流程如下主线程中创建Looper时调用Looper.prepareMainLooper()初始化主线程Looper然后调用Looper.loop()进入消息循环。子线程中通过handler.sendMessage(Message)发送消息实际上是调用sHandler.enqueueMessage()将消息插入到MessageQueue中。MessageQueue的enqueueMessage()方法中如果当前没有消息需要立即处理且需要等待就会调用nativeWake()唤醒线程。Looper.loop()无限循环调用queue.next()取消息如果没有消息或消息时间未到next()方法会调用nativePollOnce()进入休眠状态释放CPU。当有新消息时native层通过eventfd机制唤醒线程next()返回消息Looper调用msg.target.dispatchMessage(msg)最终回调到Handler的handleMessage()方法中。为什么主线程的Looper死循环不会导致ANR这个面试官必问。核心逻辑是Looper.loop()虽然是一个死循环但在没有消息时MessageQueue.next()会通过nativePollOnce()进入epoll等待状态此时线程是挂起的不消耗CPU。而Android应用的所有事件触摸、绘制、生命周期回调都需要通过Looper来驱动如果Looper停止循环应用反而会立即卡死。可以这样理解Looper不是阻塞UI的元凶而是驱动UI的引擎。我在复习这里时发现一个容易忽视的细节ThreadLocal不仅仅用于保存Looper它还被用于保存Choreographer、ViewModelStore等。所以面试官可能会问ThreadLocal的实现原理是什么答案是ThreadLocalMap每个Thread内部维护一个ThreadLocalMap以ThreadLocal作为key弱引用以实际存储的对象作为value。3.3 Binder通信机制与AIDL的使用场景Binder是Android系统中最核心的进程间通信机制笔试通常会从以下几个方面考察为什么选择Binder而不是其他IPC方式性能、安全性和易用性三方面。相对于Socket和管道Binder只需一次拷贝传统IPC需要两次拷贝性能更好相对于共享内存Binder为每个应用分配UID/PID安全性更高。这是Android选择题里常考的“为什么”需要能说出两三条理由。Binder的架构组成Client、Server、ServiceManager和Binder驱动。Client和Server分别运行在不同进程ServiceManager负责管理服务注册和查询Binder驱动工作在内核态。AIDL的作用用于快速生成Binder接口的中间层代码。定义好AIDL接口文件后构建时会自动生成对应的Stub和Proxy类开发者只需要关心业务逻辑。京东那套题里有一道场景题“进程A需要调用进程B中的某个方法获取用户信息如何设计这个跨进程调用”答案就是用AIDL定义接口进程B实现Service并在onBind中返回Binder对象进程A通过bindService拿到代理对象调用远程方法。复习Binder时我建议看一遍系统进程通信的源码至少理解BinderProxy和BinderInternal的大致职责。不需要背源码但要能画出一次Binder调用的时序图Client调用transact()数据写入Parcel通过Binder驱动传输到Server端Server的onTransact()被触发解析数据并执行方法最后将返回值写回Parcel。这个流程能画出来Binder相关题目基本都能应付。3.4 Fragment生命周期与Activity的交互细节Fragment是Android开发中非常基础但坑又非常多的组件。京东笔试有一道多选题考察Fragment生命周期与Activity生命周期在不同场景下的执行顺序。常规启动顺序当Activity启动并添加Fragment时Activity先执行onCreate()然后Fragment执行onAttach()、onCreate()、onCreateView()、onActivityCreated()最后Activity执行onStart()、onResume()。Fragment常用方法onAttach(Context context)Fragment与Activity建立关联时调用可以在这里获取Activity实例。onCreate(Bundle savedInstanceState)Fragment创建时调用但此时UI还未初始化不能操作View。onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)创建Fragment的根View返回null表示不显示UI。onViewCreated(View view, Bundle savedInstanceState)View已创建完成可以在这里初始化控件和绑定监听器。onActivityCreated(Bundle savedInstanceState)宿主Activity的onCreate已执行完成此时可以安全使用Activity的成员变量。onDestroyView()与onCreateView()对应Fragment的View被销毁但Fragment实例仍然存活。onDetach()Fragment与Activity解除关联此时不能再操作Activity。一个高频考点Fragment在旋转屏幕时的生命周期。当设备旋转导致Activity重建时Fragment不会重新创建而是会经历onPause()、onStop()、onDestroyView()、onCreateView()、onStart()、onResume()Fragment实例会保留。但如果Activity被系统完全销毁比如内存不足Fragment可能被恢复也可能丢失这取决于是否保存了Fragment的状态。我记得当时笔试有一道题目问“Fragment的onSaveInstanceState()和Activity的onSaveInstanceState()执行顺序是什么”答案是Activity先保存然后Fragment保存。原因很简单Activity需要先确保所有子View和子Fragment的状态都已经保存完毕然后才做其他状态保存。3.5 Service的启动方式与生命周期Service这块看似简单但其实容易出新题。京东那套题里有一道选择题“启动Service的两种方式有什么区别”两种方式startService()和bindService()。startService()启动一个服务服务会一直在后台运行直到自己调用stopSelf()或外面调用stopService()。调用者和Service之间的生命周期没有绑定关系调用者退出后Service仍然运行。适用于下载、音乐播放等需要长时间运行的场景。bindService()绑定一个服务调用者和Service之间建立起连接。当调用者销毁时Service会自动解绑如果没有其他绑定者系统会销毁Service。适用于需要与Service进行交互、获取Service内部状态的场景。还有一个高频考点startService和bindService混合使用时的生命周期。如果一个Service先被startService()启动后来又被bindService()绑定那么需要同时调用stopService()和unbindService()才能让Service销毁。只调其中一个Service是不会销毁的。另外Android 8.0之后对后台服务做了限制应用在后台运行时不能随意创建后台服务否则会抛出IllegalStateException提示“Background service start exception”。解决方案是使用JobScheduler或WorkManager。这一块在笔试中偶尔会出现知道有这回事就行。3.6 性能优化内存泄漏、ANR与布局优化Android性能优化相关题目在京东的笔试题里虽然不是数量最多的但往往出现在区分度高的多选题中。常见内存泄漏场景静态变量引用Activity或ContextActivity销毁后静态变量仍然持有引用导致Activity无法被回收。Handler持有Activity或View非静态内部Handler持有外部类的隐式引用如果Handler中有延迟消息未处理Activity销毁后仍然无法回收。单例持有Context或Activity单例对象在应用生命周期内一直存在如果传入的是Activity Context会导致Activity泄漏。匿名内部类持有外部类引用Runnable、AsyncTask、TimerTask等匿名内部类如果活得比外部类长就会导致泄漏。关于内存泄漏的排查笔试一般只考概念但面试官可能会追问“线上排查内存泄漏有哪些方法”标准回答是Android Studio自带的Memory Profiler LeakCanary自动化检测 MAT手动分析hprof文件。国内大厂还会用一些自研的线上内存监控方案比如字节跳动的Kernelsanitizer和腾讯的Matrix内存监控。ANR产生的原因和避免方法ANRApplication Not Responding是指应用无响应系统会弹出一个“应用无响应”的对话框。触发ANR的场景有四类普通Activity的onCreate、onResume等生命周期方法超过5秒未执行完成。前台Service的onCreate、onStartCommand等方法超过20秒未执行完成。广播接收器的onReceive方法前台超过10秒、后台超过60秒未执行完成。ContentProvider的onCreate方法超过10秒未执行完成。避免ANR的核心原则不要在主线程做耗时操作。所有IO操作、网络请求、复杂的计算都要放到子线程。同时要注意使用子线程时如果通过Handler更新UIHandler的handleMessage方法里也不能做耗时操作。注意现在很多大厂面试开始流行一个进阶问法“如何在代码中主动触发一个ANR然后抓取ANR日志进行分析”这需要你对ANR机制有更深入的理解。简单说可以通过在onCreate中执行SystemClock.sleep(6000)来触发Activity的ANR然后到/data/anr/目录查看traces.txt文件。这个操作只能在debug包中做线上绝对不能尝试。布局优化减少布局层级使用ConstraintLayout替代多层级嵌套的LinearLayout和RelativeLayout。使用include标签复用布局、merge标签减少嵌套层级。使用ViewStub延迟加载不常用的布局。避免过度绘制检查是否有多个不同的背景色叠加在同一区域。京东笔试题里有一道关于ConstraintLayout的问题问ConstraintLayout相比于其他布局的优势。答案是不言自明的扁平化视图层级、灵活的相对定位、线性约束能力、按比例约束控件尺寸性能优于嵌套布局。4. 数据结构与算法题程序员的硬功夫4.1 链表、数组与排序算法的核心考点京东校招笔试的算法部分基本不会太难但也不会送分。以链表和数组为代表的线性数据结构是必考内容。常考的经典题型包括链表反转迭代法和递归法这道题几乎是所有大厂笔试的“基础问候”。迭代法用三个指针prev、curr、next挨个反转时间复杂度O(n)空间复杂度O(1)。递归法先递归到链表尾部然后逐层返程修改next指针代码简洁但空间复杂度O(n)。合并两个有序链表可以用双指针遍历也可以用递归实现。如果扩大到合并K个有序链表就涉及优先队列最小堆的技巧。数组中的两数之和用HashMap存储已经遍历过的元素遍历到每个元素时判断目标值减去当前值的差值是否在map中。无序数组求第K大元素用快速选择算法平均时间复杂度O(n)比先排序再取值快得多。旋转数组查找目标值先判断哪一半是有序的再根据目标值所在区间缩小搜索范围。排序算法是笔试高频中的高频。快速排序、归并排序、堆排序这三大排序算法几乎每年都考不仅要会写代码还要能说清楚时间复杂度和稳定性。快速排序平均O(n log n)最坏O(n²)不稳定。核心思想是分治加分区操作partition选择基准值将小于基准的放左边大于基准的放右边。归并排序时间复杂度O(n log n)稳定。核心思想是分治加合并需要额外O(n)的空间来暂存合并结果。堆排序时间复杂度O(n log n)不稳定。核心思想是建堆加堆调整利用完全二叉树的特性实现原地排序。我还记得京东有道算法题考的是一道“合并区间”问题给定若干个区间合并所有重叠的区间。解法很经典先按区间起点排序然后遍历区间用双指针维护当前合并区间的左右边界如果下一个区间的起点大于当前边界就把当前区间加入结果集并重置边界否则就更新右边界。4.2 常用数据结构栈、队列、二叉树栈和队列看起来简单但一旦跟算法题结合就很容易出花样。“用两个栈实现队列”是校招笔试的高频题目解法是用一个栈做入队操作另一个栈做出队操作。当需要出队时如果出队栈不为空则直接弹出栈顶元素如果为空则把入队栈的全部元素倒入出队栈。这个题考察的是对两个基础数据结构的灵活应用。二叉树在2019年京东校招题中出现的频率比较高。常考的点包括二叉树的遍历前序、中序、后序递归与迭代法都要掌握和层序用队列实现。求二叉树的最大深度和最小深度递归分别求左右子树深度取大值加1即可。判断二叉树是否对称递归比较左子树的左子树和右子树的右子树。二叉搜索树的最近公共祖先利用BST的性质判断两个目标节点与当前节点的大小关系选择向左或向右递归。二叉树的层序遍历输出直接BFS用队列记录每一层的节点。我还记得京东有一道笔试题考的是**“用二叉树的前序遍历和中序遍历结果重构二叉树”**。这题在LeetCode上是105题解法很固定前序遍历的第一个节点就是根节点在中序遍历中找到根节点的位置左边是左子树右边是右子树然后递归重建。当时我刷过这道题所以做起来就很顺。4.3 动态规划校招笔试的分水岭在京东的笔试题中动态规划不算最难的但绝对是区分度最高的部分。贪心算法可能靠直觉就能想出来动态规划必须通过“状态定义-状态转移-初始化-循环推导”这套标准流程来解题。2019年那道动态规划题比较简单考的是“爬楼梯”每次可以爬1级或2级台阶爬到第n级有多少种不同的方法。这就是经典的斐波那契数列问题状态转移方程是f(n) f(n-1) f(n-2)初始状态是f(1)1f(2)2。大部分人能写出来但如果面试官追问“如果每次可以爬1级、2级或3级状态转移方程怎么写”答案是f(n) f(n-1) f(n-2) f(n-3)思路完全一样。另一个常见的动态规划题目是“买卖股票的最佳时机”这道题在京东笔试中出现过变形版本考的是只能买卖一次的情况下最大利润是多少。解法是维护一个最小值变量和一个最大利润变量遍历数组时不断更新。动态规划题目在笔试中的占比不会超过两道但建议把常见题型都刷一遍尤其是“爬楼梯”类斐波那契数列、“背包问题”类、“最长递增子序列”类。“最长递增子序列”这道题很典型O(n²)的DP做法是基础进阶O(n log n)的做法要用到二分查找和贪心思想维护一个递增序列。笔试中一般O(n²)就够用了。动态规划最核心的解题思维是不要想着一步到位先定义清楚dp数组的含义然后想清楚dp[i]是从哪些更小的状态转移过来的最后把初始状态写对。这三步做对了大部分简单和中等难度的动态规划题都能解出来。5. 网络基础与开放题容易被忽视的拉分项5.1 TCP三次握手、四次挥手及HTTP核心知识点计算机网络在京东笔试中的占比不大但知识点非常固定属于“背了就能拿分”的部分。TCP三次握手客户端发送SYN报文其中SYN1seqx。服务端收到后发送SYNACK报文其中SYN1ACK1seqyackx1。客户端收到后发送ACK报文其中ACK1seqx1acky1。此时连接建立。为什么是三次握手而不是两次核心原因是防止已失效的连接请求突然传到服务端导致服务端建立不必要的连接。生活化的类比是两个人约会甲说“周六下午三点见面”第一次握手乙收到后回复“好的周六下午三点”第二次握手甲再回复“确认收到”第三次握手。只有经过你确认、我确认、你再确认这个往返过程双方才能确认彼此的通信能力都没问题。我在实际开发中遇到过一个跟三次握手有关的问题App在弱网络环境下登录特别慢后来排查发现是TCP连接建立失败导致重试。那会儿才真的体会到为什么TCP要设计三次握手——在网络不稳定时多一次确认就多一些可靠性。TCP四次挥手主动关闭方假设是客户端发送FIN报文表示“我的数据发送完了”进入FIN_WAIT_1状态。被动关闭方服务端收到FIN后发送ACK报文进入CLOSE_WAIT状态此时服务端还能继续发送数据。服务端发送完所有数据后发送FIN报文表示“我也准备关闭了”进入LAST_ACK状态。客户端收到FIN后发送ACK报文进入TIME_WAIT状态。等待2MSL最大报文段生存时间后连接彻底关闭。为什么是四次挥手因为TCP是全双工的一方关闭不代表另一方数据也发送完了需要双方各自确认关闭。学习四次挥手时很多人容易忽略TIME_WAIT状态但如果面试问到“TIME_WAIT有什么作用”答案有两个一是确保最后一个ACK能够到达对方如果丢失对方会重发FIN客户端还能再回一次ACK二是让旧连接上的延迟报文在网络中消失避免影响新连接。HTTP与HTTPS的区别京东笔试有一道题考的就是这个列了几个选项问哪些是HTTPS的特点。HTTP是明文传输HTTPS是加密传输HTTPS默认端口443HTTP默认端口80。HTTPS在TCP之上多了一层SSL/TLS协议用于加密和解密数据。建立HTTPS连接比HTTP多一次TLS握手所以要额外消耗一些时间。HTTP状态码2xx成功200 OK、3xx重定向301永久重定向、302临时重定向、304未修改、4xx客户端错误400请求错误、401未授权、403禁止访问、404资源不存在、5xx服务端错误500服务器内部错误、502网关错误、503服务不可用。5.2 开放题与项目经历展示你思考深度的地方京东2019校招笔试题最后有一道开放题大致是“请简要描述你最满意的项目并说明你在其中承担的角色和遇到的挑战。”这类题目看似送分但其实最能反映候选人的综合能力。我在后来的面试复盘中发现开放题答得好不好直接决定了面试官问你的第一个问题是什么。如果开放题里描述了项目中的技术难点面试官大概率会在技术面中顺着这个点深入提问这时候你有充分准备的话能带一波节奏。写开放题时建议按照“项目背景-我的角色-技术方案-难点与解决-项目收获”的结构来组织。重点放在“难点与解决”上因为这最能体现你的问题定位能力和解决方案执行力。不要写流水账要写技术判断。比如描述一个“即时通讯App的消息推送模块”不要只写“我负责推送模块的开发”而是要写到这一层为了保证消息的实时性和可靠性我调研了WebSocket和长轮询两种方案最终选择了WebSocket。针对弱网络环境下的断线重连我设计了指数退避策略加上心跳包保活机制。这条技术路径的描述比干巴巴写“我实现了消息推送功能”要有说服力得多。我当时在开放题里写的是一个课程表App的课表提醒功能重点描述了因为Android系统对后台服务的限制我把方案从Service改成了AlarmManager加BroadcastReceiver组合并实现了不同Android版本的兼容逻辑。这道题后来在二面时被面试官翻出来我又现场扩展讲了Repeating Alarm和Exact Allowance的区别明显看得出面试官是认可的。5.3 完整笔试题模拟演练把知识变成分数纸上谈兵终觉浅。复习到一定阶段后强烈建议按照以下方式做全套模拟模拟环境准备找一段完整的不被打扰的时间至少90分钟手机调成飞行模式电脑上只保留浏览器和一个文本编辑器。把京东的历年笔试题和网上的Android大厂笔试题混在一起组成一套约40道题的试卷按真实考试的题型比例分配单选20道、多选10道、编程2道、简答2道。时间分配策略单选题每题控制在1分钟内多选题每题2分钟编程题每题20-25分钟简答题每题10分钟。如果某道题卡住超过3分钟先标记跳过等全部做完再回来思考。做题技巧选择题强烈建议先排除明显错误的选项。多选题尤其要注意“全选”的情况往往会有1-2道多选题答案就是ABCD。编程题先写伪代码梳理思路再翻译成正式的代码。保证边界情况比如空数组、只有一个元素也要处理到。简答题如果时间不够写关键词比写完整句子更划算。面试官阅卷看的是你有没有踩到得分点。自我评分标准笔试通过线一般在60-70分。如果你模拟测试能稳定在75分以上说明基础知识掌握得比较扎实了这时候可以开始准备面试环节的提问。如果还在60分以下别急着投简历老老实实把本文梳理的各个模块再过一遍尤其是Java集合、Handler、Activity启动模式这三个最容易拿分也最常考的部分。6. 避坑指南与独家心得6.1 校招笔试常见的五个“隐形陷阱”刷了好几套大厂笔试题之后我发现笔试中真正难的不是题目本身而是那些藏在题目背后的“坑”。把这些坑提前避开至少能提高5-10分。第一个坑多选题漏选和错选都不得分。很多平台的笔试系统多选题的判分规则是“全部选对才得分”少选一个也不算分。所以做多选题时除非你有十足的把握否则选项宁缺毋滥。我见过很多人本来能答对大部分选项结果手一抖多选了一个错误选项整道题直接零分。第二个坑编程题输入输出格式不对。笔试平台比如牛客网按样例输出匹配判分哪怕你的逻辑完全正确如果输出格式多了一个空格或者少了一个换行可能直接判错。平时练习时就养成好习惯仔细阅读输入输出的样例格式代码里对输出做统一的格式化处理。第三个坑时间分配严重失衡。有些同学在单选上纠结太久导致后面编程题只剩5分钟随便写了几句就开始交卷。策略很简单单选最多1分钟超过就跳过。先把能拿的分拿了回头再解决难题。第四个坑面试官会拿着笔试试卷来面试。笔试不是考完就结束了我的亲身经历是二面面试官打开系统看了我笔试的答题记录专门挑了几道我答错的题来问“你现在重新做一遍还是选这个答案吗”所以考完一定要把每道题都弄懂尤其是自己做错的题面试前一定要回头看。第五个坑审题不清忽略了题目里的“陷阱词”。有些题会在题干里加“不正确的”“不符合的”“除了之外”很多同学考前刷题形成惯性思维一看到熟悉的题目就凭记忆选答案结果选了“正确”选项。这种丢分最可惜。6.2 我从这套题里总结的复习方法最后分享两个我刷题时用过的“笨方法”对于打牢基础特别有效。第一个方法写技术博客或文档笔记。每复习完一个知识点用自己的话写一篇200字左右的笔记要能解释清这个知识点是什么、为什么这么设计、实际开发中怎么用。三个月后再看这些笔记如果发现读不懂自己当时写了什么说明没学明白需要重新学。这个方法很“笨”但真的有用。写的过程中你会发现自己很多“好像懂了”的知识点其实经不起推敲。第二个方法把笔试题做思维导图。以“Activity启动模式”为中心节点向外延伸出“四种模式的触发条件”“onNewIntent调用时机”“任务栈与返回栈的关系”“Intent Flag与启动模式的优先级”。把每个知识点都做成以考点为中心的导图比按章节复习要高效得多。笔试前不用翻书只看导图就能把所有考点过一遍。我在准备京东笔试时把“Handler机制”做了一张完整的思维导图从Looper.prepare()开始一路画到MessageQueue.next()怎么处理延迟消息和同步屏障。画完以后我记得特别牢到二面面试官问我“同步屏障是什么”“有什么用”的时候我都能直接答上来同步屏障是MessageQueue中一种特殊的消息标记作用是优先处理异步消息最典型的应用场景是VSYNC信号到达后优先执行界面绘制。6.3 考完试后的下一步技术面的准备方向笔试考完如果自我感觉还不错就可以马上开始准备技术面了。京东Android的技术面通常有两到三轮一面主要考察基础知识和项目经历二面围绕技术深度和设计思路展开三面是HR面。根据我的经验面试官在技术面时经常会从笔试题中挑几个点进行追问比如你在笔试中选了“singleTask适用于应用首页”面试官可能会接着问“如果多个页面都设置了singleTask它们的任务栈是怎么管理的返回行为是否符合预期”这个追问考察的是对任务栈更深层次的理解。技术面高频追问方向我整理了一下从“Handler消息机制”追问到“子线程中创建Handler会报什么错为什么”从“内存泄漏的常见场景”追问到“LeakCanary的底层检测原理是什么”从“HashMap JDK 8为什么引入红黑树”追问到“为什么阈值是8而不是16”从“HTTP与HTTPS的区别”追问到“TLS握手的具体过程是什么样的证书是怎么验证的”从“进程间通信方式”追问到“ContentProvider和Binder的关系是什么”这些追问没有标准答案但考察的都是基本功。如果你能按照我文中讲的思路把原理真正吃透哪怕追问到细节也能从容应对。还有一点提醒准备技术面时一定要把自己简历里写过的项目重新再过一遍尤其是那些你只了解表面、没有深入研究的点。面试官最喜欢在项目里挑一个你不太熟的技术细节切入然后层层追问。一个“这个我还没来得及深入”倒还好如果连续几个问题都是这个回答基本就无缘下一轮了。我在面试时被问到“Sealed Class和Enum有什么区别”这是我完全没有复习到的知识点。当时我诚实地说“这个问题我不太清楚但根据推测Sealed Class应该支持更复杂的类型变量”面试官笑了笑没追究。后来我回去查了资料才知道Sealed Class指的是密封类在Kotlin中用于表示受限的类层次结构而Enum是枚举常量。像这种没答上来的题事后一定要及时补充因为你不知道二面还会不会问同样的知识点。京东2019校招Android开发工程师笔试题说难不算特别难说简单也绝不简单。它考察的不是你刷了多少道LeetCode而是你对Android开发核心知识体系的掌握程度。这些知识无论你未来进入哪家公司做哪个方向的业务都会用得到。把基础打好比什么都强。