news 2026/9/1 21:47:09

浩鲸科技Java笔试复盘:从基础语法到并发源码的高频考点解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
浩鲸科技Java笔试复盘:从基础语法到并发源码的高频考点解析

2020届秋招那会儿,我在牛客网上刷到浩鲸科技的Java开发岗笔试邀请。说实话,当时对这家公司的了解不算深,只知道是通信行业出身的软件服务商,业务面很广。抱着多积累经验的心态,我点开了笔试链接。

整套题做下来,我的第一感受是:题目不算偏,但覆盖面非常宽,细节陷阱特别多。它不像一些大厂那样上来就是一道hard级算法题压阵,而是把Java基础、集合源码、并发、JVM、数据库、框架使用、场景设计全部铺开考了一遍。换句话说,它考察的不是你会不会某个冷门知识点,而是你日常学习Java时有没有真正理解那些“最常用”的东西。

这篇文章我就结合当时的笔试经历,把考察到的核心知识点、我当时的答题思路,以及事后复盘发现的丢分点,逐块整理出来。不管你是准备投递浩鲸科技,还是在准备其他公司的Java笔试,希望这篇复盘能帮你少走一些弯路。

1. 浩鲸科技2020届Java笔试整体回顾:题量、结构与应对策略

1.1 笔试形式与题型分布

浩鲸科技这场笔试是在牛客网进行的,总时长印象中是90分钟还是120分钟,题量不算小。题型大致分为四类:

  • 单选题:约15题,覆盖Java基础语法、面向对象、异常、常用类库等,每题考察的点都比较细。
  • 多选题:约10题,主要考察集合框架、并发包、JVM相关概念,多选少选都不得分,这一点比较折磨人。
  • 简答题:4题左右,需要手打文字作答,一般考察的是某个机制的原理,比如HashMap的扩容过程、线程池的执行流程等。
  • 编程题:2到3题,题目难度适中,以字符串处理、数组操作、排序为主,不涉及特别复杂的算法。

这个结构透露出的信号很明确:浩鲸科技的笔试更看重基础知识的广度和代码功底,而不是算法竞赛式的思维。如果你把大量时间花在刷leetcode hard题上,而忽略了Java基础源码的深入理解,这场笔试的得分反而不一定高。

1.2 判分逻辑与答题节奏

多选少选不得分这一点,直接影响我的答题策略。对于没把握的多选题,我尽量只选两个最有把握的选项,放弃挑战全对的可能。这样做虽然上限分低一些,但能保住下限。事后和一起笔试的同学交流,确实有同学因为多选贪多,反而把本来能拿到的分丢掉了。

时间分配上,我大致是按这个节奏来的:

  • 单选+多选:30分钟
  • 简答题:25分钟
  • 编程题:30分钟
  • 剩余时间检查+补漏:10到15分钟

实际做下来,编程题比我预想的要基础,反而是简答题因为要写清楚“原理说理”,比想象中费时间。建议后续考生给简答题预留更多的时间,不要急着赶编程题。

这里补充一个实操心得:笔试开始前先快速扫一遍所有题目的类型和数量,心里大致有个时间预算。我看到有些同学在一道多选题上纠结了五六分钟,导致后面编程题时间不够,这是最不划算的。

2. 基础语法与JVM考点:送分题与送命题的分水岭

2.1 String、==与equals的经典陷阱

单选里出现了一道很经典的String题目,大概意思是判断几个字符串比较表达式的输出。

这类题的核心在于搞清楚两件事:

  • ==比较的是引用地址,equals比较的是内容(前提是没有重写过)。
  • 字符串常量池会让直接赋值的字符串在池中复用,而new String()会创建新的堆对象。

我当时遇到的一个变体是这样的:

String s1 = "java"; String s2 = "java"; String s3 = new String("java"); String s4 = s3.intern(); System.out.println(s1 == s2); // true System.out.println(s1 == s3); // false System.out.println(s1 == s4); // true System.out.println(s3 == s4); // false

这里最容易被忽略的是s4 = s3.intern()intern()方法会尝试把字符串放入常量池,如果常量池中已经有了相同内容的字符串,就直接返回常量池中的引用。因为s1已经让常量池中存在了"java",所以s4拿到的就是s1那同一个引用。

这种题考察的是对JVM字符串常量池机制的掌握程度,不光是背结论,还要知道背后的存储逻辑。笔试前我刚好系统梳理过这个知识点,所以做起来比较顺畅。

2.2 重载与重写、静态绑定与动态绑定

多选里有一个题考察的是重载和重写的区别,选项涉及的维度包括:方法名是否相同、参数列表是否相同、返回值是否能不同、权限修饰符的要求、异常声明的要求等。

区分重载和重写的关键在于理解它们的设计初衷

  • 重载是同一个类中多个方法使用相同方法名、不同参数列表,目的是让同一个操作在不同输入类型下表现不同,属于编译期多态。
  • 重写是子类重新实现父类的方法,要求方法签名完全相同(参数列表和返回类型兼容),属于运行期多态。

有个容易忽视的知识点:重写时的返回值类型可以是父类返回类型的子类型(协变返回类型)。例如父类是Object get(),子类可以重写为String get()

另一个常考的点是静态方法。静态方法可以被子类隐藏,但不能被重写,因为静态方法属于类而不是实例,在编译期就已经确定了调用目标。我在做题时看到这个选项,差点混淆,好在想起了“静态绑定”和“动态绑定”这两个概念:

  • 静态方法调用在编译期就能确定,称为静态绑定。
  • 实例方法调用需要根据运行时的实际对象类型来确定,称为动态绑定(虚方法表机制)。

2.3 JVM内存区域与对象创建过程

简答题里有一道是关于JVM运行时内存区域的划分以及对象头的组成。这类题在笔试中的出现频率很高,我从Java对象创建的过程切入来作答。

一个Java对象从new到回收,大致经历这几个区域:

  • :对象实例和数组的主要存储区域,几乎所有对象的创建都在这里发生。堆又分为新生代(Eden、Survivor from、Survivor to)和老年代。
  • 虚拟机栈:每个线程私有一块栈,栈中存放栈帧。每调用一个方法,就会创建一个栈帧,栈帧里包含局部变量表、操作数栈、动态链接、方法返回地址。
  • 方法区/元空间:存储类信息、常量、静态变量、即时编译器编译后的代码。在JDK 8之后,永久代被移除,改为元空间,使用本地内存。
  • 程序计数器:当前线程执行字节码的行号指示器,分支、循环、跳转、异常恢复等都依赖它。

回答“对象创建过程”时,我按这个顺序展开:

  1. 类加载检查:虚拟机遇到new指令时,先检查这个类是否已被加载、解析、初始化。
  2. 分配内存:根据指针碰撞或空闲列表的方式,在堆中划分出一块确定大小的内存。
  3. 内存空间初始化为零值:这一步保证了对象的实例字段可以不赋初值就直接使用(局部变量不行)。
  4. 设置对象头:存储对象的运行时元数据,如哈希码、GC分代年龄、锁状态标志、类元数据指针等。
  5. 执行构造方法:将对象初始化到预期的状态。

这道题的加分点在于回答“对象在栈上分配的可能性”。虽然绝大多数对象分配在堆中,但JVM的逃逸分析技术会尝试把不逃逸的对象分配在栈上,随方法结束自动销毁,避免GC压力。能提到这一点,说明你不是单纯背八股,而是理解过JVM的实际优化。

2.4 类加载机制:双亲委派模型的答题要点

有一道单选考了双亲委派模型,问的是某个自定义类加载器在加载类时的查找顺序。

双亲委派模型的含义是:当一个类加载器收到类加载请求时,它不会自己尝试加载这个类,而是把请求委派给父类加载器去完成,每一层都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器(Bootstrap ClassLoader)中。只有在父类加载器反馈自己无法完成加载时,子加载器才尝试自己加载。

这样设计最重要的原因是安全:比如java.lang.String这个类,无论哪个类加载器想加载,最终都会委托给启动类加载器去加载,保证核心类库只加载一份,不会被用户自定义的恶意代码冒充。

笔试中常见的追问是“如何打破双亲委派模型”,常见思路是重写loadClass()方法而不去重写findClass()方法。因为loadClass()里实现了双亲委派的逻辑,自定义加载器通常是重写findClass()来完成具体的查找逻辑,而不是破坏委派过程。

3. 集合框架与并发源码:HashMap、线程池这类题怎么答出层次

3.1 HashMap底层结构与扩容机制

简答题里有一道非常典型的题目:描述HashMap从JDK 7到JDK 8的变化,以及put方法的执行流程。

JDK 7时代,HashMap的底层是数组加链表,链表插入使用头插法。在高并发场景下,多个线程同时扩容可能引发循环链表,导致get操作出现死循环。

JDK 8的改进有几个关键点:

  • 链表改为尾插法,避免扩容时出现循环链表。
  • 当链表长度超过8且数组长度大于等于64时,链表会转化为红黑树,把查找时间从O(n)优化到O(log n)。
  • 扩容时不需要像JDK 7那样重新计算hash,只需要看原来的hash值新增的bit位是0还是1,为0则留在原位置,为1则移动到“原位置+旧容量”的位置。

这里我补充一下为什么转红黑树要链表长度大于8。根据泊松分布,在负载因子0.75的情况下,链表长度达到8的概率已经非常低(约千万分之一)。也就是说,只有当哈希分布出现严重问题时才会触发这个阈值,此时用红黑树来兜底。这个细节如果能在作答时提到,会显得你确实研究过源码而不只是背结论。

关于HashMap的初始化容量,笔试中还可能考到“给定初始容量16,扩容后容量是多少”这种题目。扩容是2倍,16变32,32变64,这个没啥好说的。真正有意思的是Map.EntryvsNode的区别,以及JDK 8之后红黑树的节点类型TreeNodeLinkedHashMap.Entry的子类,这影响了迭代时的一些行为。不过一般笔试不会考这么深。

3.2 ConcurrentHashMap的锁粒度演进

有一道多选题问到ConcurrentHashMap在JDK 7和JDK 8中的区别,选项包括锁机制、数据结构、并发度等。

JDK 7的ConcurrentHashMap使用分段锁,整个Map被分为16个Segment(默认并发度16),每个Segment是一把独立的ReentrantLock。不同的线程操作不同的Segment互不干扰,所以并发度上限是16。

JDK 8抛弃了分段锁,改为CAS加synchronized的方式。锁的粒度从Segment细化为单个桶(数组的每个下标位置)的头节点。这意味着只要两个线程操作的是不同桶中的元素,就可以真正并发执行,并发度远高于16。

JDK 8的put过程大概是:

  1. 如果table为空,执行initTable()初始化。
  2. 如果根据hash定位的桶为空,通过CAS尝试直接放入节点。
  3. 如果ForwardingNode标记表明正在进行扩容,则当前线程协助完成扩容。
  4. 如果桶不为空,则synchronized锁住桶的头节点,然后在链表或红黑树中执行插入。

我当时在回答中特别强调了一点:CAS只有一次成功的机会,失败就进入锁的流程。这种“先乐观后悲观”的并发策略,在JDK 8里处处可见,理解了这个思路,ConcurrentHashMap很多设计就好懂了。

3.3 线程池参数与执行流程

简答题里出现了描述ThreadPoolExecutor执行流程的题目,这是Java并发的经典考点。

核心参数就七个:

  • corePoolSize:核心线程数。
  • maximumPoolSize:最大线程数。
  • keepAliveTime:非核心线程空闲的最大存活时间。
  • unit:存活时间单位。
  • workQueue:任务队列。
  • threadFactory:线程工厂。
  • handler:拒绝策略。

执行流程可以浓缩成四个判断:

  1. 当前线程数是否小于核心线程数?小于则直接新建线程执行任务。
  2. 线程数已大于等于核心线程数,尝试把任务丢进工作队列,队列满了则进行下一步。
  3. 当前线程数是否小于最大线程数?小于则新建非核心线程执行任务。
  4. 线程数已达到最大,且队列已满,触发拒绝策略。

拒绝策略有四种:AbortPolicy(抛异常)、CallerRunsPolicy(调用者线程直接执行)、DiscardPolicy(丢弃)、DiscardOldestPolicy(丢弃队列中最老的,重新提交当前任务)。

笔试容易考的是:当核心线程数被突然调大时,会怎么处理?答案是线程池不会马上创建新的核心线程,而要等待新的任务到来时才会创建。ThreadPoolExecutor的prestartAllCoreThreads()方法可以提前启动所有核心线程,但这在实际项目中很少用。

我当时的经验是:遇到线程池相关的题,一定要把“任务是怎么一步步被处理的”这条脉络说清楚,中间不要跳过“队列满了”这个前提。很多同学一上来就写拒绝策略,忘了说明是“线程数达到最大值且队列已满”这个双重前提默认情况下线程池是什么行为。

3.4 手写单例的并发分析

编程题的旁边还有一道简答,给出了几种单例写法并要求指出线程安全问题。其中一种写法是这样的:

public class Singleton { private static Singleton instance; public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }

这种懒汉式写法很明显是线程不安全的,两个线程同时判断instance == null后,可能各自创建一个实例。标准解法是加双重检查锁:

public class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }

这里最关键的是volatile关键字。它保证了两件事:一是可见性,二是禁止指令重排序。instance = new Singleton()在字节码层面不是一步操作,而是三步:

  1. 分配内存空间。
  2. 初始化对象。
  3. 将引用指向内存地址。

如果不加volatile,步骤2和3可能被CPU乱序执行,另一个线程可能拿到一个还没初始化完成的对象引用。这种“半初始化”问题很隐蔽,笔试时值得好好展开说明。

4. 数据库与框架题:从MySQL索引到MyBatis的细节

4.1 索引失效场景与SQL优化

笔试中涉及数据库的题目主要集中在MySQL索引上,尤其是索引失效的几种场景和SQL优化的基本思路。

常见的索引失效场景包括:

  • 对索引列使用函数计算,如WHERE YEAR(create_time) = 2020
  • 隐式类型转换,比如索引列是varchar,但查询条件是数字类型。
  • 左模糊匹配,LIKE '%java'导致无法使用索引。
  • 联合索引不符合最左前缀原则。
  • 查询条件中对索引列进行了表达式运算。
  • 优化器判断全表扫描比走索引更高效时,也会放弃索引。

有一道题目设计的场景是:在(a, b, c)上建了联合索引,问哪些查询能用上索引。这个知识点不难,关键在于a = 1 and c = 3这种查询中,a能用索引,但c因为中间缺少b的条件,无法使用索引。很多同学会误以为只要是联合索引中的列就能用,忽略了最左前缀。

我当时的答题策略是:先摆出联合索引B+树的组织方式,说明索引的排序规则是“先按第一列排序,再按第二列排序……”,所以跳过了某一列,后面的列就失去了有序性,自然无法用于索引查找。这样说清楚了原理,就不需要死记硬背。

4.2 事务隔离级别与MVCC

有一道多选考的是事务隔离级别,题目给出了几种隔离级别,让选出“不会出现脏读”的选项。

MySQL的四种隔离级别是:

  • 读未提交(Read Uncommitted):允许读取未提交的数据,脏读、不可重复读、幻读都可能发生。
  • 读已提交(Read Committed):只能读到已提交的数据,解决了脏读,但不可重复读和幻读仍可能发生。
  • 可重复读(Repeatable Read):同一事务内多次读取结果一致,解决了不可重复读,但幻读仍可能发生。MySQL的InnoDB在实现上通过间隙锁解决了幻读问题。
  • 可串行化(Serializable):完全串行化,隔离级别最高,性能最低。

这道题不光是考概念,还考了一个细节:MySQL默认隔离级别是可重复读,而不是读已提交。这是Oracle的做法,两者不同,有的同学容易搞混。

MVCC(多版本并发控制)的原理其实可以简单理解成:每行记录有多个版本,不同事务看到不同的版本。它基于隐藏的DB_TRX_IDDB_ROLL_PTR字段,以及undo log中的版本链来实现。快照读的时候,根据当前事务的read view来判断哪些版本可见。可重复读和读已提交的差别就在于read view的生成时机:

  • 读已提交:每条查询语句都生成一个新的read view
  • 可重复读:同一个事务内复用同一个read view,所以读到的数据始终一致。

我当时在简答题中画了这个对比(用文字描述),明显感觉答题的深度上了一个档次。这也是我反复提醒自己的一个原则:笔试中回答原理类问题,尽量从底层机制说起,不要只列表面结论

4.3 MyBatis的#{}与${}区别

框架相关的题目里,MyBatis几乎必考#{}${}的区别。这题不难,但实操中极易踩坑。

  • #{}是预编译处理,MyBatis会把它替换成?占位符,然后通过PreparedStatement参数绑定来设置值,可以防止SQL注入。
  • ${}是字符串拼接,MyBatis直接把参数值拼接到SQL语句中,存在SQL注入风险。

既然${}有风险,为什么还要用?答案是有些场景下它是必须的,比如参数是表名、列名、排序字段时不支持预编译。如果你项目里用了MyBatis-Plus的动态条件查询,底层构造排序字段时也需要用拼接的方式。

需要注意的是:即便是表名、列名这类需要用${}的场景,也必须采用白名单校验,避免用户输入直接拼进SQL。比如排序字段,可以在代码里做一个枚举校验,只允许ascdesc,其他一律拒绝。这个经验是我在实际项目里踩过坑之后总结出来的,笔试里如果被追问“怎么安全地使用${}”,能答出白名单校验,会是很好的加分项。

4.4 Redis常用数据结构选型

笔试里还有一道关于Redis的题,考察的是各数据结构的适用场景。题目大概给出了“缓存用户信息”“统计UV”“排行榜”这几个场景,让你选择对应的数据结构。

  • 缓存用户信息:可以用String(JSON序列化)或Hash(字段级别读写)。
  • 统计UV:用HyperLogLog,虽然有一定的误差率,但内存占用极小。
  • 排行榜:用ZSet,通过分数排序,天然支持按名次范围获取。

MySQL和Redis的经典组合类是常考重点。Redis作为缓存,需要考虑缓存穿透、缓存击穿、缓存雪崩的处理。缓存穿透是指查询一个必定不存在的数据,导致请求直达数据库;解决思路是布隆过滤器或者缓存空值。缓存击穿是指某个热点key突然失效,大量请求同时落到数据库;解决思路是加互斥锁,或者设置逻辑过期时间。缓存雪崩是指大量key同时失效,解决思路是给过期时间加随机值,避免同一时刻大面积失效。

笔试时候能把这些点都答上,数据库这部分的分数基本就稳了。别只答“用Redis做缓存”就完了,得说出怎么用、遇到问题怎么办

5. 手写算法与场景设计题:笔试中最考验应变的部分

5.1 排序算法的手写套路

浩鲸科技的编程题中没有要求写快排或归并,而是出了相对简单但更贴近业务的题目。不过我还是建议把冒泡、选择、插入、快排这四个基础排序都准备到手写一遍的程度。万一题目就是让手写排序,至少不能在这里翻车。

一个常见的编程题是:给定一个整数数组,要求将所有的偶数排在前面,奇数排在后面,并且保持相对顺序不变。

这道题其实就是“稳定分区”问题。最简单的实现方式就是用一个新数组做两次遍历:第一次把偶数放进结果数组,第二次把奇数放进去。这样时间复杂度是O(n),空间复杂度是O(n)。

如果要求原地操作,思路就和冒泡排序有点像,从后往前把相邻的奇偶交换到“不对”的位置,但是要保持稳定就需要多一些操作。我当时的做法是直接用新数组,简单又不容易出错。

5.2 字符串处理题的边界

还有一道编程题是字符串相关,印象中是把字符串中的连续空格替换为单个空格。这类题看起来很基础,但边界条件很多。常见的边界包括:

  • 字符串开头、结尾有空格。
  • 连续多个空格。
  • 字符串为空或长度为0。
  • 字符串中只有空格。

我当时用了一个比较稳的方法:先去掉首尾空格,然后用正则或遍历处理中间的多余空格。笔试环境不一定允许网络搜索,建议自己熟悉Java中StringBuilder的用法,因为字符串拼接在笔试中经常用到,而StringBuilder是性能最优且最常用的选择。

5.3 场景设计题的答题框架

编程题之外的简答里,有一道场景设计类型的题目:假设有千万级用户量的系统,如何设计一个用户登录状态校验方案。

我当时的答题思路分了三层:

第一层,用Redis存储token。用户登录成功后生成一个token,存到Redis里并设置过期时间,后端每次请求都从Header中取出token到Redis中校验。这是最常见、也是最容易想到的方案。

第二层,考虑分布式会话的问题。单机Tomcat的Session无法在多节点共享,直接把Session放到Redis,或者使用JWT这类无状态token来避免Session共享问题。

第三层,考虑安全与性能的平衡。token的过期时间、续期策略、token失效后的处理方式,都是需要明确设计的。比如用户长时间不操作时,可以用滑动过期策略,每次请求时刷新过期时间。

这个答题框架的好处是:先给一个能跑的方案,再指出这个方案的缺陷,然后逐层优化。这种“演进式回答”在任何场景设计题中都非常通用。面试官或判卷人看到的不只是你知道某个技术,而是你具备架构式的思考习惯

6. 复盘总结:投递笔试题时我做对了哪些准备

浩鲸科技的这场笔试考完,我整体的感觉是:题都不算难,但真要全部答好,靠的是平时的积累,不是临阵磨枪。复盘之后,我总结了三个值得分享的经验。

6.1 高频考点的优先级排序

如果你的准备时间有限,我建议按这个优先级来复习Java笔试题:

  1. 集合源码:HashMap、ConcurrentHashMap、ArrayList扩容机制。
  2. Java基础语法细节:String常量池、重载重写、装箱拆箱、异常处理。
  3. 并发基础:synchronized与ReentrantLock、线程池执行流程、CAS与volatile。
  4. JVM内存区域与类加载机制
  5. MySQL索引与事务
  6. Spring/MyBatis/Redis使用层面的常见问题。

把前三条弄扎实,基本能覆盖大多数公司的Java笔试核心考察范围。

6.2 答题时的几个细节习惯

  • 多选不确定就少选,尤其在“少选不得分”的规则下,保住确定项比冲全对更重要。
  • 简答不要只写结论,把你得出这个结论的推导过程和底层原理也写出来,这是区分“背过”和“理解”的关键。
  • 编程题先想清楚边界条件再动手,写完最好在心里跑一遍测试用例。
  • 遇到不会的题先跳过,把确定能拿到的分数拿到手,再回来研究不会的题。

6.3 笔试之后的衔接

笔试之后紧接着的一般是技术面。浩鲸科技这类公司,笔试中出现的知识点大概率在面试中还会以追问的形式出现。比如你笔试答了ConcurrentHashMap的JDK 8实现,面试官很可能追问:为什么JDK 8要用synchronized而不是ReentrantLock?这个话题如果能在笔试后提前想清楚,面试时就不会被问住了。

我当时还做了一件事:把笔试中所有没把握的题目重新整理了一遍,对照源码和官方文档,把每个知识点吃透。这样做的好处是,即使笔试分数不理想,面试时还能通过深入交流展示自己的真实水平。

最后再提醒一句:笔试刷题网站上的模拟题库值得反复做。浩鲸科技的题目并不完全是原创的,很多考点在牛客、力扣的题库中都能看到类似版本。多刷几遍,熟悉常见考法和答题节奏,真正上考场时会从容很多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/1 21:45:30

网易Unity笔试深度解析:底层原理与工程实践避坑指南

说实话,网易的校招笔试在游戏行业里一直算有分量的,尤其是Unity3D开发工程师这个岗位,投的人多,筛得也狠。我印象里2020届正式批这套试卷,整体风格不是那种"背一背八股就能过"的类型,它对底层原理…

作者头像 李华
网站建设 2026/9/1 21:40:00

B站2023校招算法笔试卷B拆解:高频考点与实战策略

去年秋招帮学弟做模拟面试的时候,他拿了一套哔哩哔哩2023校园招聘算法方向的笔试卷B出来,说连着做了两遍,选择题还好,一到编程题和问答题就心里没底。我翻了翻这套卷子,发现它其实很有代表性——它不只是B站的笔试&…

作者头像 李华
网站建设 2026/9/1 21:32:39

数据开发笔试复盘:SQL、数据倾斜与数仓建模要点

我当年拿到这套“哔哩哔哩2020校园招聘数据开发方向笔试卷(二)”的时候,第一反应是:这不就是一份SQL加Java的混合卷吗?后来认真刷完才发现,数据开发笔试的考察逻辑和普通后端开发完全不同,它更看…

作者头像 李华
网站建设 2026/9/1 21:32:03

Ubuntu零基础入门到精通【5.5讲】:PPA 软件源的使用与风险——当官方仓库不够用时,你该怎么做?

🏆 本文收录于 《滚雪球学 Ubuntu》 专栏。 本专栏面向有一定计算机基础,但尚未系统学习 Linux / Ubuntu 的读者,采用“滚雪球式学习法”:先装好、再会用、再理解、再优化、再实战,带你从第一次进入 Ubuntu 桌面 / 终端开始,逐步掌握 Ubuntu 的日常使用、命令操作、软件…

作者头像 李华
网站建设 2026/9/1 21:24:53

3Ds Max2027安装包+教程网盘资源下载与安装指南

如大家所熟悉、了解的,3Ds Max是3D Studio Max的简称,也被大家称为3Dmax,它是一款专业三维建模、动画和渲染软件‌,广泛应用于影视、游戏、建筑可视化等领域,是行业标杆级的三维创作工具。目前来看,3Ds Max…

作者头像 李华