今日八股:三轮全对,String 拼接那句还漏了个版本

今日八股:三轮全对,String 拼接那句还漏了个版本

今天三轮全过,Java 三题、前端八小问、数据库网络三题,一个没错。复盘的时候没找到硬伤,倒是抠出来几个版本细节和叫法,都是当场觉得自己说清了、面试官一追问可能就要停一下的地方。

Java:String 拼接那句漏了 JDK 版本

循环里写 s = s + i; 拼字符串,代码能跑,为什么说这样写不好?换写法怎么改?什么场景还得用另一个「带锁」的兄弟?

我答的是:String 不可变,每拼一次就产生一个新对象,然后改原变量存的地址,循环里堆一堆用完就扔的临时字符串,所以该用 StringBuilder;带锁的那个是 StringBuffer,多线程里用。

结论没错,但中间夹了一句「直接修改 String 底层也是 StringBuilder 再 toString」。这句只在 JDK 8 及以前成立。那时候 javac 确实把它编译成 new StringBuilder().append(...).toString() 一串;JDK 9 之后改成了 invokedynamic 调 StringConcatFactory,不再走 StringBuilder。面试官要是接一句「从哪个版本开始不是这样」,我就卡住了。

另外两处是措辞。判断 key 存不存在用的是 containsKey,我写成了 containerKey,白板上写错方法名挺亏的。还有「keySet 再 get 会多遍历一次」,准确说是每个 key 都多走一次哈希查找,一千个 key 就是一千次额外查找,元素少的时候根本看不出来。

前端:v-show 不是白拿的

v-if 和 v-show 都能按条件显示隐藏一个元素,底层差别在哪?一个元素反复切来切去,用哪个更合适?

这轮八个小问全对。v-if 是不渲染 DOM,v-show 是渲染出来再加 display:none;频繁切换用 v-show,因为 v-if 反复增删节点会引来大量重排重绘。reactive 那个坑也答上来了:reactive 返回的是代理,变量整体重新赋值等于指向了一个新的普通对象,响应式就断了,改法是 Object.assign(state, {...})。

补一句我当时没想到的:v-show 也不是白拿的。它无论真假都先把元素渲染出来,首屏开销比 v-if 大;挂在 template 上无效,也不能跟 v-else 配。

数据库:COUNT 里写哪个

users 表 10 个用户,orders 表里只有 7 个用户下过单。JOIN 和 LEFT JOIN 返回的结果有什么不一样?没匹配上的用户,orders 那边的字段显示什么?

三问都过了:内连接只出 7 条,左外连接出 10 条,没下过单的用户在 orders 那几个字段上是 NULL;内连接是两边都匹配上的行,外连接是主表全量配上次表里匹配的部分。

第三问「所有用户加各自的订单数,一个单都没下的也得显示、订单数显示 0」值得单独记:连接用左外连接,COUNT 里面写 o.id,不能写星号。写星号会把没匹配上的那一行也算进去,结果显示成 1 而不是 0。这种题面试官就是在等你写不写星号。

网络:半连接,不是僵尸连接

为什么 TCP 要三次握手,两次行不行?少一次会出什么问题?

我答的是不行,两次的话服务端没法确认客户端收到了自己的 SYN+ACK。客户端要是没收到,服务端这边已经把连接当建好了,白白挂着一个连接占资源。

道理是对的,要抠的是叫法:服务端那种状态叫半连接,挂在 SYN_RCVD 上占着半连接队列,说「半开连接」也规范;「僵尸连接」面试官听得懂,但不是标准说法。第三问「浏览器发 HTTP 请求在握手之前还是之后」,答之后,对:连接建起来才发数据。

← 返回文章列表