免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

网易云音乐Java实习笔试复盘:基础语法、集合与并发考点全解析

网易云音乐Java实习笔试复盘:基础语法、集合与并发考点全解析 网易云音乐的实习生招聘说到底考的是你有没有真正动手写过Java代码。这套2018年的题目我印象很深它不搞偏题怪题也不考什么特别冷门的框架所有考点都扎在Java基本功上运算符、集合、排序、JVM、多线程。这套题的筛选逻辑其实很简单——你不是来面试架构师的你是来写业务代码的所以你要证明自己能把基础语法写对、把常用类的原理说清、把简单的并发场景设计明白。作为一个Java开发实习生岗位的笔试云音乐这套题的价值到今天也不算过时尤其是如果你正在准备秋招或者找Java实习拿来练手和复盘非常合适。我尽量还原这套题的考察范围、易错点以及我的解题思路顺便把当年踩过的一些坑也一并写出来。1. 网易云音乐Java实习岗笔试这套题到底想筛选什么样的人很多同学复习笔试喜欢盯着“难偏怪”的东西刷但网易这套实习生笔试题的导向非常明确它要的是基础扎实、能直接干活的人。云音乐的Java开发实习生业务上和推荐、歌单、评论、用户体系这些模块强相关所以笔试不会考你分布式中间件也不会考微服务治理而是把精力放在你日常写代码一定会碰到的语言细节和常用类库上。1.1 题型分布与真实考场节奏整套卷子的题型构成大致是这样的单选和多选混合的选择题数量在20到30道之间覆盖Java语法、集合框架、JVM、多线程、网络编程等。手写代码题一般是1到2道以排序、链表、字符串处理为主需要在线上IDE里自己处理输入输出。场景设计或逻辑分析题通常会结合云音乐的业务场景比如歌单并发操作、点赞计数、缓存设计等。考试时长一般是120分钟。我当时的感受是选择题部分如果你基础够扎实40分钟以内能过完一遍代码题一定要留足30分钟以上因为线上IDE没有本地IDE那么顺手调试速度会明显变慢。很多人前面选择题磨太久最后代码题只写了一半就交卷这是最亏的。网易的笔试平台用的是类似于牛客网的那套OJ系统代码题需要完整读取输入、输出结果不是写个方法签名就能过。平时练习的时候不要只会在IDE里跑main方法一定要习惯用Scanner或者BufferedReader去处理标准输入。1.2 从题目风格反推岗位要求云音乐这个部门的技术栈以Java为主业务上对并发量有一定要求。笔试题目里凡是出现多线程、集合并发安全相关的考点都不是随便考考而是对应到真实业务里的歌单并发编辑、评论高并发写入、热歌榜计数更新这些场景。另外网易笔试有个特点特别喜欢考“你以为你会了但其实你没完全会”的知识点。比如HashMap的扩容条件、枚举能不能定义抽象方法、Lambda表达式里变量捕获的限制条件。这些考点在教科书里都有但如果你只是背概念、没有亲手写过很容易在选项里被干扰项带偏。所以这套题筛选的画像很清晰基础扎实、平时动手写代码多、对Java常用类库底层有一定好奇心的人。如果你的目标就是Java开发实习生这套题是一份非常好的对照清单。2. 选择题里的语法死角运算符优先级、枚举与Lambda的易错点选择题里占比最大的永远是Java基础语法。这个部分在很多人看来是送分题但网易偏偏喜欢在最容易混淆的地方埋坑。我在复盘这套题的时候发现有三类语法题几乎每年都会出现运算符与表达式求值、枚举的高级用法、Lambda表达式与函数式接口。2.1 运算符与表达式自增自减和移位运算的翻车现场运算符相关的题目考察点通常不是“你知道和-”而是优先级和求值顺序。比如下面这道经典题int i 0; i i i; System.out.println(i);这道题考察的是自增自减在表达式中的求值时机。i是先取i的当前值0参与运算然后i变为1i是先将i自增为2再取2参与运算。所以表达式的值是2最终i的值也是2。但这类题真正的坑不在于结果而在于你在考场上是否足够冷静。网易的题目里还经常混入三目运算符和赋值运算符的组合比如int a 5; int b 10; boolean flag false; System.out.println(flag ? a : b);简单分析一下flag为false走b分支b变为11输出11a不变。这类题本身不难但如果你在做题时没有把运算优先级写在草稿纸上凭感觉选答案很容易在a和a上翻车。还有一个高频点是位运算。云音乐这种音视频业务在权限控制、状态位标记上经常会用到位运算。选择题里常见的考法是int x 8; int y x 1; int z x 1;是带符号右移是无符号右移。正数的情况下两者结果一样但如果是负数会把最高位补0结果会变成一个很大的正数。考场上看清楚题目给的是正数还是负数这种题就是送分题。2.2 枚举类型不只是简单的常量列表Java枚举是笔试的常客但很多人对枚举的理解停留在“替代常量”的层面。网易的题目会考得更深一些。比如enum Color { RED(1), GREEN(2), BLUE(3); private int code; Color(int code) { this.code code; } public int getCode() { return code; } }这个枚举的定义其实包含了很多隐藏知识点枚举可以有构造器但构造器必须是私有的枚举可以有成员变量和方法枚举可以实现接口但不能继承类因为它已经隐式继承了java.lang.Enum。选择题还喜欢考values()和valueOf()方法。values()返回枚举数组valueOf(String)根据名字字符串返回对应的枚举常量如果找不到会抛IllegalArgumentException。另外一个容易出错的地方是枚举和switch的组合。在Java 5以后switch支持枚举类型case语句里不能带枚举类名直接写枚举常量名即可。这个细节很多人写代码的时候没注意做题就暴露了。2.3 Lambda表达式函数式接口的语法糖Lambda在Java 8之后就是面试必考了。网易笔试不太会直接问“Lambda的语法有哪些”而是把它藏在集合操作的题目里。典型考法是ListString list Arrays.asList(b, a, c); list.sort((s1, s2) - s1.compareTo(s2));这里考的是List.sort()方法接收一个Comparator接口而Comparator是一个函数式接口所以可以用Lambda表达式实现。更深一层的考点是“有效final”这个概念。Lambda表达式里如果引用了外部局部变量这个变量必须是final或者是effectively final初始化之后不再被修改。比如int base 10; Runnable r () - System.out.println(base); base 20; // 这里会编译报错这个限制的原因是Java设计者为了保证Lambda捕获的变量是稳定的避免多线程环境下数据不一致。笔试选择题经常给你一段代码问哪一行会编译报错这个点年年都有。3. 集合框架送分题与送命题HashMap的put流程你背对了吗集合框架是Java笔试的重头戏网易特别偏爱HashMap。我在复盘这套题的时候发现光HashMap一个类就能延伸出七八个考点从数据结构到hash算法从扩容机制到线程安全性每一层都能出题。3.1 HashMap的存储结构数组加链表加红黑树JDK 8之后的HashMap采用数组链表红黑树的结构。数组的每一个位置叫一个桶bucket当多个key的hash索引落到同一个桶时用链表把它们串起来当链表长度超过阈值8并且数组长度大于等于64时链表会转换成红黑树。这个结构在选择题里的考法通常是给你一段代码问某个对象经过几次比较能找到。比如hash冲突严重时链表查询是O(n)红黑树查询是O(log n)为什么到8才转红黑树因为红黑树的节点占用空间是链表节点的两倍左右只有冲突足够严重时树化的空间和时间优势才划得来。3.2 hash方法与put流程从源码角度理解HashMap的hash(Object key)方法不是直接用key.hashCode()而是把hashCode的高16位和低16位做异或运算static final int hash(Object key) { int h; return (key null) ? 0 : (h key.hashCode()) ^ (h 16); }这个做法的目的是让高16位也参与到索引计算中。因为数组的默认长度是16计算索引时用(n - 1) hash低位相同的hashCode在数组长度较小时冲突概率特别高。把高16位异或进来可以打散低位减少碰撞。put的流程大致是先对key计算hash然后通过(n - 1) hash定位到桶。如果桶为空就直接插入如果不为空遍历链表或红黑树如果找到了相同的key就替换value找不到就追加到链表尾部或者树中。插入完成后检查元素个数是否超过阈值超过就扩容。这个流程在笔试里可以变成很多选择题比如“HashMap什么时候会树化”“替换value时返回的是什么”“如果key是nullhash是多少”。3.3 扩容机制与默认负载因子为什么是0.75HashMap的默认容量是16负载因子是0.75。当元素个数超过容量 * 负载因子 12时触发扩容容量翻倍变为32。为什么负载因子是0.75而不是0.5或1.0从时间和空间两个维度看负载因子太大比如1.0数组利用率高但hash冲突会变多链表变长查询效率下降负载因子太小比如0.5冲突少查询快但空间浪费严重。0.75是JDK作者在大量测试基础上选出来的一个均衡值大多数场景下空间和时间的综合表现最好。扩容的细节里有个更容易考的关联点多线程环境下HashMap扩容可能导致死循环。JDK 7里扩容时用头插法并发扩容容易出现环形链表导致get操作死循环。JDK 8改成了尾插法死循环问题得到缓解但多线程下数据丢失和覆盖的问题仍然存在所以并发场景要用ConcurrentHashMap。3.4 选择题里常见的Map实现横向对比除了HashMap网易笔试还会把Hashtable、LinkedHashMap、TreeMap、ConcurrentHashMap放在一起考。Map实现是否线程安全底层结构迭代顺序HashMap否数组链表红黑树无序Hashtable是方法加synchronized数组链表无序LinkedHashMap否数组链表红黑树双向链表插入顺序或访问顺序TreeMap否红黑树按键排序ConcurrentHashMap是数组链表红黑树CASsynchronized无序选择题最喜欢问的就是“哪个Map可以按key排序”——答案是TreeMap“哪个Map可以保持插入顺序”——答案是LinkedHashMap“哪个Map不允许null key”——答案是Hashtable和ConcurrentHashMap。这些结论看起来零散但它们背后都有清晰的实现逻辑。4. 手写代码题冒泡排序和快速排序在笔试里的正确打开方式代码题是笔试里最拉分的一项。网易这套题里的代码题没有到LeetCode Hard的程度但也不是简单到让你默写排序算法是出现频率最高的一类。4.1 冒泡排序能写对不难能写好很难冒泡排序的基础写法大家都会public static void bubbleSort(int[] arr) { for (int i 0; i arr.length - 1; i) { for (int j 0; j arr.length - 1 - i; j) { if (arr[j] arr[j 1]) { int temp arr[j]; arr[j] arr[j 1]; arr[j 1] temp; } } } }但这道题真正考察的是你有没有优化意识。如果在一轮遍历中没有任何交换发生说明数组已经有序可以提前结束。优化版public static void bubbleSort(int[] arr) { for (int i 0; i arr.length - 1; i) { boolean swapped false; for (int j 0; j arr.length - 1 - i; j) { if (arr[j] arr[j 1]) { int temp arr[j]; arr[j] arr[j 1]; arr[j 1] temp; swapped true; } } if (!swapped) { break; } } }如果数组原本就有序优化后时间复杂度从O(n^2)降到O(n)。这种优化在笔试判卷时非常加分因为说明你不只是背了代码而是理解了排序的本质。4.2 快速排序分治思想与边界条件快排在笔试里比冒泡更常考因为它考察的不只是代码而是你对递归和分治的理解。标准写法如下public static void quickSort(int[] arr, int left, int right) { if (left right) { return; } int pivot partition(arr, left, right); quickSort(arr, left, pivot - 1); quickSort(arr, pivot 1, right); } private static int partition(int[] arr, int left, int right) { int pivot arr[right]; int i left - 1; for (int j left; j right; j) { if (arr[j] pivot) { i; int temp arr[i]; arr[i] arr[j]; arr[j] temp; } } int temp arr[i 1]; arr[i 1] arr[right]; arr[right] temp; return i 1; }快排手写题最容易出问题的地方在边界条件。很多人递归的时候把left right写成left right当数组只有两个元素时就会栈溢出;还有人在partition里把j right写成j right导致pivot自己被交换。这些细节平时写代码不觉得考场上没有断点调试只能一遍过必须靠平时养成的肌肉记忆。快排的时间复杂度平均是O(n log n)最坏情况下是O(n^2)。最坏情况发生在每次partition都选到最大或最小的元素作为pivot比如数组已经完全有序时固定选最后一个元素。笔试选择题如果问“快排最坏情况发生在什么时候”答案就是序列基本有序且pivot固定取一端的时候。4.3 在线笔试的输入输出坑网易的代码题在OJ系统上判分输入输出处理不当会导致0分。Java在线笔试常用Scanner读入数据Scanner sc new Scanner(System.in); int n sc.nextInt(); int[] arr new int[n]; for (int i 0; i n; i) { arr[i] sc.nextInt(); }这段代码本身没问题但要注意如果输入规模很大Scanner的读取速度会比较慢用BufferedReader会更稳妥BufferedReader br new BufferedReader(new InputStreamReader(System.in)); String[] parts br.readLine().split( ); int n Integer.parseInt(parts[0]);另外如果题目要求输出排序后的数组注意输出格式是不是要求用空格分隔、最后一个元素后面不能有空格。这些细节虽然不算算法核心但往往是笔试里真正决定你是否能通过的那几分。5. 内存与并发考点OOM排查思路和云音乐场景设计题JVM和多线程在网易这套题里占的比例不低因为云音乐这种高并发业务非常依赖这两块。选择题通常会考JVM内存分区和OOM的类型场景题则会把并发问题包装成业务场景来问。5.1 OOM的几种常见类型热搜词里出现过OutOfMemoryError: insufficient memory这个其实是Java进程向操作系统申请内存时被拒绝时抛出的错误。笔试选择题更常考的是这几类java.lang.OutOfMemoryError: Java heap space堆内存不足创建对象时堆空间已满。java.lang.OutOfMemoryError: GC overhead limit exceededGC回收效率极低连续多次GC都只回收不到2%的堆内存。java.lang.OutOfMemoryError: unable to create new native thread无法创建新的线程说明线程数已达上限或者操作系统内存不足。java.lang.StackOverflowError栈溢出常见于递归没有终止条件。选择题的考法通常是给你一段代码让你判断会抛出什么异常。比如无限递归调用的方法会抛出StackOverflowError而不断往List里add对象会抛出OOM: Java heap space。5.2 云音乐场景下的内存问题缓存对象与内存泄漏如果场景题结合云音乐最常见的设计是本地缓存歌单列表、用户会话信息等突然有一天线上服务OOM了让你排查。合理的排查思路是先用jstat -gcutil看堆内存各区域的使用率再用jmap -dump:formatb导出堆快照用MAT或者JProfiler分析哪个对象占用了大量内存。常见的元凶是用HashMap当缓存但只往里放不清理导致key越来越多或者IO流没有关闭底层DirectByteBuffer持续堆积。5.3 多线程场景题歌单并发编辑与点赞计数云音乐的场景题最具代表性的就是点赞和计数器。比如设计一个歌曲的点赞数统计服务要求不能超卖也不能计数不准。这道题考察点很明确用synchronized或ReentrantLock保证原子性但锁粒度要大影响性能。更好的方案是用AtomicInteger或者LongAdder利用CAS保证原子性并发度高。再进一步如果点赞量非常大可以把计数更新操作放到消息队列里异步处理先更新缓存再异步落库。这种题的思路不是让你写出唯一正确答案而是看你能不能分析出不同方案的取舍能不能想到缓存、异步、原子类这些常见的并发优化手段。6. 我的实际答题顺序与复盘经验复盘这套题我认为答题顺序对成绩的影响被很多人低估了。网易的笔试时间不算特别宽裕如果没有策略地从头做到尾很容易在某一道多选题上卡太久导致后面的代码题没时间写。6.1 成功率最高的答题顺序我推荐的顺序是先快速过一遍所有选择题把有把握的先选完拿不准的先标记跳过然后立刻做代码题因为代码题分值高、写起来耗时不确定留到最后容易慌代码题写完后再回头做那些被标记的选择题。这样做有几个原因第一选择题如果卡在某道题上每多花一分钟都是亏损代码题可能因为这一分钟就少写一个边界条件第二代码题需要清醒的头脑和充裕的时间先写代码可以在状态最好的时候拿到高分第三回头再看选择题时通常会有新的思路因为后面的代码题可能用到了相关的知识点。6.2 一些考场细节网易的笔试题是多选和单选混在一起多选题目会明确标注。做多选题时最常见的丢分原因不是不会而是选多了或者选少了。我的习惯是按判断题来做每个选项单独判断对错再和题目要求对照看到底是“正确的有”还是“错误的有”。代码题如果第一遍没调试通过不要反复提交。因为OJ系统有些是实时判分并扣分的反复提交会拉低最终分数。最好把代码在本地IDE里或者脑子里仔细走一遍测试用例确认无误后再提交。代码题里还有一个经典坑题目给的示例与真实测试用例可能差异很大。比如示例是5个元素的数组排序真实测试用例可能是10万个元素的排序这时候冒泡排序可能直接超时。所以在笔试前把快排、归并排序这种O(n log n)的排序算法练熟是一个性价比极高的备考动作。6.3 给后来人的三点经验第一不要把复习重点放在背诵所谓的“八股文”上背得再熟选择题换个问法就认不出来了。更好的方式是读源码HashMap、ArrayList、String这些常用类的源码并不算长读一遍之后你对API背后行为的理解会完全不同。第二调试代码要用自己的测试用例去验证边界条件。排序算法要测空数组、单个元素、逆序数组链表题要测只有一个节点和两个节点的情况字符串题要测空串和超长串。这些边界条件是笔试判分的重点也是平时练习最容易忽略的。第三不要把网易云音乐的这套题当成一次性测试做过就丢。做完之后把你的错题整理成一个清单每个知识点都追问一句“为什么”比如为什么ConcurrentHashMap在JDK 8里改用CAS加synchronized、为什么枚举的构造器必须是private。这种追问式复盘的效果比刷十套新题都强。我在复盘这套题时最大的感受是网易的考题其实一直都在暗示岗位日常要做的事——写正确的语法、用对集合类、处理高并发问题、排查内存故障。如果你能顺着这些考点把对应的源码和原理吃透通过笔试只是起点真正入职后面对云音乐这种量级的业务你会发现笔试里考的东西工作中每天都在用。
返回列表