每日5题Java面试系列(7):进阶篇(String的intern()方法,Java 9 的变化、浏览器乱码怎么解决、UTF-8成为主流编码的原因、BOM的作用与争议)

各位晚上好,周一愉快(距离周五还有4天)

建议先看基础篇,再来看进阶篇。

系列介绍

欢迎来到"Java面试基础篇"系列!本系列旨在帮助Java开发者系统性地准备面试,每天精选至少5道经典面试题,涵盖Java基础、进阶、框架等各方面知识。坚持学习21天,助你面试通关!
基础面试题:
每日5题Java面试系列基础(1)
每日5题Java面试系列基础(2)
每日5题Java面试系列基础(3)
每日5题Java面试系列基础(4)
每日5题Java面试系列基础(5)
每日5题Java面试系列基础(6)

1. 如何理解 String 的 intern() 方法?

核心理解
intern()字符串驻留(String Interning) 的核心方法,用于将字符串对象手动加入 JVM 的字符串常量池(String Pool),并返回池中的唯一引用。

关键点与亮点

  • 内存优化:通过复用常量池中的字符串,减少重复对象的内存占用。
  • ==equals 的差异
    String s1 = new String("Hello");  
    String s2 = s1.intern();  
    System.out.println(s1 == s2); // false(堆对象 vs 常量池对象)  
    System.out.println("Hello" == s2); // true(均指向常量池)  
    
  • 性能权衡
    • 优点:适合大量重复字符串场景(如日志处理)。
    • 缺点:驻留过程需哈希计算,可能引发常量池竞争(JDK 7+ 已将常量池移至堆中,缓解 PermGen OOM 问题)。

面试亮点

提到 JDK 7 的常量池从 PermGen 迁移到堆内存,结合 -XX:StringTableSize 调优(默认 60013,可扩容至百万级)。


2. Java 9 对 String 内部实现的改变及原因

改变内容

  • 存储结构:从 char[] 改为 byte[] + byte coder(标记编码类型)。
  • 编码支持
    • coder = 0:Latin-1(1 字节/字符)
    • coder = 1:UTF-16(2 字节/字符)

设计动机

  • 内存节省:Latin-1 字符串(如纯英文)内存占用减少 50%
  • 性能提升:减少内存带宽压力,尤其适合大量短字符串场景(如 JSON 解析)。

代码验证

String latin = "Hello";      // 内部使用 Latin-1 编码(1 字节/字符)  
String emoji = "😊";         // 内部使用 UTF-16 编码(2 字节/字符)  

面试亮点

指出 Compact Strings 特性对微服务内存占用的实际影响(实测堆内存降低 10%~20%)。


3. 为什么需要 StringBuilderStringBuffer

核心原因

  • 不可变性的代价String 的每次拼接(如 +)会生成新对象,导致 O(n²) 时间复杂度
  • 可变字符序列
    • StringBuilder:非线程安全,性能更高(单线程首选)。
    • StringBuffer:线程安全(方法加 synchronized),适合多线程拼接。

性能对比

// ❌ 低效(生成多个中间对象)  
String result = "";  
for (int i = 0; i < 10000; i++) {  
    result += i;  
}  

// ✅ 高效(原地修改)  
StringBuilder sb = new StringBuilder();  
for (int i = 0; i < 10000; i++) {  
    sb.append(i);  
}  

面试亮点

提到 JVM 对 + 的优化:编译期常量折叠(如 "a" + "b" 变为 "ab"),但循环内拼接仍需手动优化。


4. 不可变对象的设计模式适用场景

核心优势

  • 线程安全:无需同步(如 StringBigDecimal)。
  • 缓存友好:哈希值、计算结果可缓存(如 Pattern 的编译正则)。
  • 防御性编程:防止被篡改(如数据库连接参数)。

经典场景

  • 值对象:货币、日期、坐标(record 类型在 JDK 14+ 强化了不可变性)。
  • 并发共享数据ConcurrentHashMapKey 必须不可变。
  • 函数式编程:Lambda 表达式捕获的变量需为 final 或等效不可变。

面试亮点

对比 享元模式(Flyweight)String 常量池是享元模式的典型实现。


5. Java 中处理不同编码的字符串

关键 API

  • 编码String.getBytes(Charset.forName("GBK"))
  • 解码new String(byte[], "UTF-8")

最佳实践

  • 显式指定编码:避免依赖平台默认编码(如 new InputStreamReader(is, StandardCharsets.UTF_8))。
  • 通用方案
    // 读取文件时指定编码  
    Files.readAllLines(Paths.get("file.txt"), Charset.forName("GB18030"));  
    

面试亮点

强调 StandardCharsets 常量类(JDK 7+)优于字符串硬编码(避免拼写错误)。


6. 浏览器乱码问题解决方案

常见原因

  • 服务端与浏览器编码不一致(如服务端返回 GBK,浏览器解析为 UTF-8)。
  • HTTP 头缺失:未设置 Content-Type: text/html;charset=UTF-8

解决步骤

  1. 统一编码:全栈使用 UTF-8(数据库、后端、前端)。
  2. HTTP 头显式声明
    response.setContentType("text/html;charset=UTF-8"); // Java Web  
    
  3. HTML Meta 标签(双保险):
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
    

面试亮点

提到 BOM 问题:UTF-8 文件开头的 BOM 可能导致某些浏览器解析异常(如  乱码)。


7. 为什么 UTF-8 成为互联网主流编码?

核心优势

  • 兼容性:ASCII 字符仍占 1 字节(英文场景高效)。
  • 变长编码:节省空间(中文通常 3 字节,而 UTF-16 固定 2/4 字节)。
  • 无字节序问题:无需 BOM(与 UTF-16/UTF-32 不同)。
  • 自同步性:可从任意字节恢复字符边界(鲁棒性强)。

数据支持

W3Techs 统计显示:98% 的网站使用 UTF-8(2023 年数据)。


8. BOM(字节顺序标记)的作用与争议

定义

  • BOM(Byte Order Mark):U+FEFF 字符,用于标记文本的字节序(大端/小端)和编码类型。

常见场景

  • UTF-16/UTF-32:必须用 BOM 标识字节序(如 FE FF 表示大端)。
  • UTF-8不建议使用 BOM(RFC 3629 规定 UTF-8 无字节序问题)。

问题案例

  • Java 文件编译错误:UTF-8 with BOM 可能导致 package 语句解析失败。
  • Linux 脚本执行异常:Shebang(#!/bin/bash)前出现 BOM 会报错。

面试亮点

指出 Maven/Gradle 构建工具会过滤 BOM,但 IDE(如 Notepad)可能自动添加。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值