技术复盘:那些被你忽略的底层原理与常见知识盲区 1. 为什么这些知识点总被我们顺手漏掉最近在做技术复盘的时候我突然意识到一个挺尴尬的事实很多知识点我并不是不会而是它们被我条件反射式地跳过了。比如说你天天写0.1 0.2知道结果不对但要是真让你讲讲为什么不对、怎么在业务里规避很多人会卡壳。我管这类东西叫最近遗漏的知识点——不是刚学的忘记了而是学得太早、用得太顺结果连原理都被顺手丢在了角落。1.1 不是不会是知识变成了条件反射人在长期使用一个东西以后会进入一种自动驾驶状态。就像你开车时不记得自己什么时候换过挡写代码时也不记得自己为什么会写出if (x null) throw ...这种判断。知识一旦变成条件反射就很难被重新审视。我举个非常典型的例子几乎每个后端开发都能脱口而出HTTP是 80 端口、HTTPS是 443 端口。但你再追问一句HTTPS 建立连接的时候第一步先做什么很多人会愣住然后含糊地说先加密。加密什么用什么加密公钥从哪来证书是怎么验证的这些问题就是典型的遗漏知识点——它们躺在你大脑的某个角落但你已经很久没有调用过它们了。这类知识点有几个共同特征太基础基础到你觉得不用想就知道于是真的不再想。太常用每天在用反而从来没去查过底层机制。被高层工具遮蔽框架帮你封装好了你只调接口不看实现。我在复盘的时候给自己定了一个规矩凡是能毫不犹豫说出结论但讲不出推导过程的知识点全部算遗漏。这个标准听起来苛刻但确实能帮你挖出不少平时懒得深想的东西。1.2 够用就好与知识盲区的形成另一个隐蔽的原因是够用就好的心态。很多知识点我们只掌握了够用的那一层下面还有一整座冰山没看过。拿 Redis 来说绝大多数人都知道它是内存数据库快支持多种数据结构。但问一个稍微深入一点的问题Redis 的字符串类型底层到底用的是 SDS简单动态字符串还是直接 C 字符串为什么不用 C 字符串这时候很多人就沉默了。平时用 Redis 做缓存、做分布式锁确实不需要关心底层实现但这些底层设计决定了它为什么快、为什么能支持某些操作这是排查性能问题时的关键线索。我把这个现象总结成一个知识水位模型掌握层次典型表现算不算会听说过知道名字不知道干嘛的不算会用能写对 API能调通流程算基础会懂原理能讲清底层机制与取舍算真会能优化能基于原理解决疑难问题算精通大部分人的会停留在第二层。而最近遗漏的知识点恰恰就藏在第三、第四层的区域里。你不需要每个知识点都精通但你得知道自己遗漏了哪些。知道自己不知道这本身就是一种很稀缺的能力。2. 我的查漏补缺思路与整理框架发现遗漏只是第一步怎么系统地把它们捞回来才是重点。我以前也犯过收藏即学会的毛病——看到一篇好文章先收藏收藏完就再也不看了。这次我用了一套新的整理方法实测下来效率高很多。2.1 用主动回忆代替被动翻阅主动回忆Active Recall是一个认知心理学里的老概念但在技术学习里特别管用。最简单的做法是不看书、不搜资料直接在纸上或者文档里把你脑子里认为的知识结构画出来、写出来。我自己的操作流程是这样打开一个空白 Markdown 文件。写下最近半年工作中高频使用的所有技术名词HTTP、HTTPS、Redis、数据库索引、TCP、进程线程、哈希、JVM 或 Node.js 事件循环看你的技术栈。对每个名词用 30 秒时间凭记忆写下我知道了什么越具体越好。写完以后再逐个去翻文档或者源码把写错、写漏、写模糊的地方全部标红。这个过程非常裸——你没有参考只能依赖大脑里真正存下来的东西。很多遗漏知识点在这个环节就会暴露出来。比如我写 TCP 的时候只写了三次握手但为什么是三次而不是两次这个关键问题我完全没写出来。这就说明我根本没理解握手的意义只是背住了结论。2.2 以面试题和教学场景作为照妖镜另一个很有效的方法是给自己出题或者拿经典面试题来检验。我不太建议直接去背面试题而是建议把面试题当成知识盲区的探测针。比如这些题为什么浮点数不能直接用比较数据库索引为什么会失效最左前缀匹配到底是什么意思HashMap的默认大小为什么是 16而不是 10进程和线程的根本区别是什么协程又是怎么回事如果一个接口变慢了你会从几个方向排查这些问题有一个共同点它们都在逼你解释为什么。如果你只能答出就是这样记住就行那恭喜你你找到了一个遗漏的知识点。我还特别喜欢用能不能讲给别人听来检验自己的掌握程度。有一次我尝试不查资料白板讲一遍 HTTPS 的连接过程讲了三分钟就开始卡壳——证书链验证那块我根本没搞明白。于是我老老实实回去翻了 RFC 文档和相关博客把那块补上。教是最好的学这句话在查漏补缺的场景里尤其成立。2.3 建立自己的知识索引卡片很多人做笔记喜欢大段大段摘抄结果整个笔记变成一本书的复印件看起来厚实际上没法用。我的做法是建立知识索引卡片每张卡片只写一个知识点结构固定为一句话结论用最简单的话说明这个知识点是什么。底层原理写清楚关键机制最好带一张手画示意图或简单代码。常见坑点这个知识点经常导致什么问题。一句话类比用生活场景帮助自己快速回忆。比如我之前对哈希冲突的理解就很模糊每次听到开放寻址链地址法都似懂非懂。后来我用卡片的形式整理了一遍写了一句话类比哈希表就像一排储物柜哈希函数决定你的东西放哪个柜子冲突就是两个人看中了同一个柜子。开放寻址是去旁边找空柜子链地址法是同一个柜子里多挂几个袋子。写完这张卡片以后再遇到HashMap的源码分析我理解起来就顺畅多了。这种卡片的好处是丢失的只是记忆的检索路径卡片可以帮你重建路径而不是重新学一遍整个知识体系。3. 最近梳理出的几个典型遗漏知识点接下来这部分是全文的重头戏。我把自己最近整理卡片时发现的几个典型遗漏知识点列出来不追求大而全只讲那些平时以为会、实际没搞懂的东西。3.1 浮点数精度不只是0.1 0.2的问题很多人知道0.1 0.2 ! 0.3但问为什么只能答出浮点数有精度问题。这个答案太笼统了真正的关键是浮点数的二进制表示本身就是不精确的。0.1转换成二级制小数是什么是一个无限循环小数。就像十进制里1/3 0.3333...永远写不完一样二进制里0.1也写不完。计算机的存储位数是有限的所以只能截断截断就产生了误差。在 JS 里0.1 0.2的结果是0.30000000000000004是因为两个不精确的数相加误差被放大了。在 Java 里float和double同样有这个问题。实操建议金额计算千万不要用float/double要用BigDecimalJava、DecimalPython或整数分单位存储。比较浮点数时不要用用差值小于一个极小阈值如Math.abs(a - b) 1e-9。如果数据库存金额用decimal类型不要用float。这个知识点我早就知道结论但直到最近整理为什么的底层逻辑时我才真正意识到精度问题不是某个语言的 bug而是 IEEE 754 标准下所有二进制浮点数的宿命。理解了这一点看任何语言的浮点坑都一通百通。3.2 HTTP 与 HTTPS 的底细别只记端口号我刚才提到 HTTPS 的过程这里展开讲一下。很多人能流利说出HTTPS 比 HTTP 多了 SSL/TLS 加密但再深入一层就卡壳。HTTPS 的核心是混合加密传输数据用对称加密速度快但对称加密的密钥需要用非对称加密来传递。整个连接大致分这几步客户端发起请求告诉服务器自己支持的加密协议版本。服务器返回自己的证书证书里有公钥。客户端验证证书是否可信看证书链是否由受信任的 CA 签发、域名是否匹配、是否过期。验证通过后客户端生成一个随机对称密钥用服务器公钥加密后发给服务器。服务器用自己的私钥解开得到对称密钥。后续双方都用这个对称密钥加密通信。这里的证书验证是最容易被遗漏的环节。以前我以为浏览器看到 HTTPS 就代表安全其实不是——HTTPS 不等于绝对安全它依赖于证书系统。如果证书链有问题或者某个 CA 被攻破HTTPS 的保护就会打折扣。这个知识在实际开发和接口联调中有个很实际的用处当你遇到HTTPS 证书过期导致接口请求失败的时候你能快速定位问题而不是一脸懵地重启服务。我印象很深的一次是生产环境突然报了一堆证书错误同事都以为是网络问题我检查了证书有效期发现正好过期续期后马上恢复。这就是懂原理和只会用的差别。3.3 数据库索引的本质与失效场景索引是大厂面试必问、日常开发必修的知识点。但绝大多数人停留在建索引能让查询变快的层面。我这次复盘把索引的知识点重新理了一遍挑出两个最容易被漏掉的部分。第一个索引为什么能快索引的底层主要是 B 树。B 树的优势在于它是多路平衡搜索树树的高度很低。一个三层高的 B 树就能存储几百万条数据意味着查询时最多只需要做几次磁盘 I/O就能定位到目标。而全表扫描相当于一本书从头读到尾索引相当于配合目录去翻页。你以为你在用目录其实你用的是 B 树的叶子节点链表——这个细节就足够聊半天了。第二个索引为什么会失效这是最容易在实际中踩坑的。常见的失效场景包括对索引列使用函数或计算比如WHERE YEAR(create_time) 2024索引会失效。隐式类型转换比如索引列是字符串但查询条件传了数字可能无法走索引。不符合最左前缀匹配原则。如果你建了(a, b, c)联合索引查询条件是b 1 AND c 2这个索引基本用不上因为跳过了最左的a。使用LIKE %关键词这种前置模糊匹配大概率失效。我身边的真实案例一个列表页比较慢排查后发现查询条件里写了WHERE status 1 AND DATE_FORMAT(create_time, %Y-%m-%d) 2025-01-01。这个DATE_FORMAT直接让create_time的索引失效改成create_time 2025-01-01 AND create_time 2025-01-02之后查询从 800ms 降到 20ms。这就是典型的没搞懂原理靠直觉写 SQL。3.4 哈希冲突你以为的 O(1) 其实是 O(n)HashMap的get操作号称平均 O(1)但这个前提是哈希函数足够均匀。一旦发生哈希冲突最坏情况下多个 key 落在同一个桶里链表的查询会退化到 O(n)。Java 8 里链表长度超过 8 会转红黑树就是为了缓解这个问题。但很多人不知道的是自定义对象的 hashCode 写得不好会导致 HashMap 性能灾难性下降。比如两个对象返回相同的 hashCode每次查询都会遍历链表。我在一次代码评审里见过一个类把hashCode()固定返回1当时那个接口平时数据量小看不出来上线后数据量一大接口直接超时。排查半天才发现是 HashMap 里的链表已经长到几十万每次 get 都是线性扫。所以这个知识点的实操结论是重写equals()一定要重写hashCode()。hashCode()要尽量分散别用太简单的规则。如果 key 是自定义对象可以直接用不可变对象比如String、Integer做 key别自己造轮子。哈希冲突还有一个衍生知识点HashMap 的默认容量是 16负载因子是 0.75。这个16和0.75背后是有讲究的。0.75 是空间和时间的一个折中太大容易频繁冲突太小浪费空间。很多人只记住这两个数字不理解它们是经验的平衡点遇到为什么默认 16这种追问就露馅了。4. 实操过程我是怎么把知识点真正补进脑子里的知道了遗漏的知识点怎么把它们真正变成自己的这部分的实操经验是我最近觉得最有价值的也是建议大家直接抄作业的部分。4.1 把知识点写进代码验证一次光看文章、做笔记知识点永远是别人的知识。我的做法是把每个遗漏的知识点变成一个最小可运行的小例子亲自跑一遍。比如浮点数精度问题我写了一个 Java 小程序BigDecimal a new BigDecimal(0.1); BigDecimal b new BigDecimal(0.2); System.out.println(a.add(b)); // 0.3 double c 0.1; double d 0.2; System.out.println(c d); // 0.30000000000000004运行结果一摆出来原理就变成很直观的感受。再比如 TCP 的三次握手我没有装 Wireshark直接在一台 Linux 服务器上用了tcpdump抓包看 SYN、SYN-ACK、ACK 的过程。实践一次比背十遍都管用。还有一次为了理解数据库索引失效我建了一张测试表插了十万条数据分别用explain看两种写法的执行计划。看到type ALL全表扫描和计算结果条数变化的时候我对隐式类型转换导致索引失效的理解彻底脱敏了。抽象的原理一旦落成明确的输出记忆会牢固得多。4.2 用讲给别人听来检验掌握程度第二步是我最近才养成的习惯。每次整理完一个知识点的卡片我会试着把它讲给同事听或者在没有听众的情况下自言自语录音。讲的时候注意能不能用大白话讲清楚能不能回答别人的追问有一回我给别人解释 B 树为什么比二叉树更适合做数据库索引。我原本准备了一大堆术语从高扇出到叶子节点顺序存储结果才开口讲两句自己就觉得不对劲——扇出这个词本身就解释不清楚。于是我去查了资料才知道高扇出意味着同样的数据量B树高度更低、查找路径更短并且叶子节点用链表串起来天然适合范围查询。这几个点是我以前没真正内化过的。检验标准的经验之谈如果你讲一个知识点的时候句子结构是因为...所以...而且能连续讲出三个以上的因为说明你基本掌握了。如果只能讲出它就是这样设计的说明还没搞懂。4.3 定期回炉与遗忘曲线遗忘是人的天性遗漏的知识点补回来以后还会再次漏掉。我的解决方案是间隔复习。我不喜欢用复杂的记忆软件就用一个最简单的办法在日历上每两周设置一个知识回炉日。到了这一天不干别的专门翻看自己整理的知识卡片重点看常见坑点和一句话结论。看到能秒懂的就过看到模糊的就立刻去查资料当场把卡片更新一遍。还有一个我强烈推荐的做法——写月复盘。每个月底花二十分钟写下这个月踩过的坑、修复过的 bug、学到的知识点。不用写很长三五条也行。这个月复盘不是给别人看的是给你自己以后的自己看的。三个月后再回头看你会发现自己已经忘掉了很多当时以为学会了的东西而那些真正留下的、依然能在脑子里清晰复现的知识点才是你真正掌握的。5. 常见问题与避坑指南最后分享一些实际执行过程中遇到的问题和我的处理思路这些经验比单纯的知识点更值钱。5.1 光看不练回头就忘这是最常见的问题也是我反复掉进去的坑。看文章的时候觉得这个我懂了合上文章就忘了。原因很简单你看懂的是作者的思路不是你的思路。我的破解方法是三步法看完一篇文章立刻把浏览器标签页关掉。用一句话在卡片上写下这个知识点是干嘛的。尝试不看原文写出一个最小示例或画出流程。三步都能完成才关卡片。三步完不成说明还是没学会回头再看一遍原文但这次不要往下读先自己再试一遍。试不出来有哪些步骤就说明那一步是你的知识缺口重点补那一步就行。5.2 知识点太多整理变成负担有些人一复盘就给自己列了一份十大必学清单结果压力太大坚持了两天就放弃了。我一开始也犯过这个毛病清单列了二十多个知识点每天看到都焦虑。后来我调整策略一次只整理一个领域。这个月重点补网络基础那就只看 HTTP、TCP、DNS 这些下个月再看数据库、并发。把一个领域的知识点卡片都建立起来以后再换下一个。领域之间确实有交叉但不用刻意求全先一个个打透比同时挖浅坑强得多。另外整理时不用追求完美笔记。卡片只要对你有检索价值就行不需要排版精美、图文并茂。我之前花很多时间给笔记画各种花哨的流程图结果画完就忘了内容。现在我用最朴素的文字加一两个关键代码块反而复盘的频率更高。5.3 深度、广度、性价比的取舍最后一个建议是关于学习策略的。不是所有知识点都需要往深挖也不是所有遗漏都必须立刻补。我给自己定了一个三问标准这个知识点和工作内容相关吗它影响我排查问题或做技术决策的频率高吗它能否帮助我理解其他关联知识三个问题里至少答出两个是才值得花时间深挖。如果只是单纯觉得不懂心里痒那就控制时间比如给自己限时 30 分钟查资料了解个大致框架就收手。知识海洋是无穷的与其什么都略懂皮毛不如在核心领域打深几个点其他领域保持知道它在、需要时能找到资料的状态就好。我个人在实际操作中的体会是知识点的遗漏并不可怕可怕的是你连自己漏了什么都不知道。定期复盘、建立卡片、动手验证、讲给别人听这套组合拳帮我解决了不少自己都没意识到的盲区。如果你最近也一直在输出却总觉得心里空空的不妨停下来花一个下午做一次最近遗漏的知识点梳理。这个过程刚开始可能有点痛苦因为你可能会发现自己什么都不会但坚持一两轮以后那种越学越踏实的感觉是刷一百篇文章都换不来的。