interview
interviewduck-java-backend
为什么 Java 中的 String 类被设计为 final

面试鸭 Java 后端面试题, 为什么 Java 中的 String 类被设计为 final?

面试鸭 Java 后端面试题, 为什么 Java 中的 String 类被设计为 final?

QA

Step 1

Q:: 为什么 Java 中的 String 类被设计为 final?

A:: Java 中的 String 类被设计为 final 是为了确保字符串的不可变性(immutable)。不可变对象在多线程环境下是线程安全的,因为其状态不能被修改。这简化了代码,避免了许多潜在的同步问题。同时,String 被广泛用作哈希表的键,若其值在使用过程中能被修改,会导致不可预测的行为和安全漏洞。不可变性还允许字符串池(string pool)的使用,提高了内存利用率和性能。

Step 2

Q:: Java 中的不可变对象有哪些?

A:: 除了 String 类,Java 中还有许多不可变类,例如 Integer、Long、Float、Double、BigInteger 和 BigDecimal。这些类的实例在创建后其状态不能被修改。不可变对象在多线程编程中非常有用,因为它们天然是线程安全的。

Step 3

Q:: 如何创建一个不可变类?

A:: 要创建一个不可变类,应遵循以下几个原则:1) 使用 final 声明类;2) 所有字段使用 final 声明;3) 在构造函数中初始化所有字段;4) 不提供修改字段的方法;5) 确保类中的所有可变对象字段也是不可变的,或者在访问这些字段时提供保护性拷贝。

Step 4

Q:: String 类的内部结构是什么样的?

A:: String 类内部使用一个字符数组(char[])来存储字符串数据。在 Java 9 之前,String 使用的是 char 数组,而在 Java 9 及以后版本,String 改用 byte 数组以减少内存占用。String 类还有一个 hash 字段用于缓存字符串的哈希码,以提高哈希操作的性能。

Step 5

Q:: 什么是字符串池?

A:: 字符串池(string pool)是 Java 中的一个特殊内存区域,用于存储字符串字面量和通过 intern() 方法显式创建的字符串。字符串池的存在是为了节省内存,因为相同的字符串字面量在池中只会存储一次。字符串池由 JVM 自动管理,字符串的不可变性使得池中的字符串可以安全地被多个引用共享。

用途

面试中询问这些内容的目的是评估候选人对 Java 语言核心特性的理解,特别是不可变对象的设计及其在并发编程中的应用。这些知识在实际生产环境中非常重要,尤其是在开发高性能、多线程应用时。了解 String 类的设计和不可变对象的使用有助于编写线程安全且高效的代码,避免常见的并发问题和内存泄漏。\n

相关问题

🦆
解释什么是哈希码以及为什么 String 类会缓存它?

哈希码是对象的整数表示,通常用于哈希表中来快速查找对象。String 类缓存哈希码是为了提高哈希表操作的性能,因为字符串的哈希码计算相对昂贵,缓存可以避免重复计算。

🦆
什么是保护性拷贝defensive copy?

保护性拷贝是一种设计模式,用于防止可变对象在类外部被修改。它通常在构造函数、getter 或 setter 方法中使用,通过创建对象的副本而不是直接返回对象的引用来保护对象的内部状态。

🦆
描述 StringBuilder 和 StringBuffer 的区别?

StringBuilder 和 StringBuffer 都是用于构建可变字符串的类。主要区别在于 StringBuffer 是线程安全的,因为它的方法是同步的,而 StringBuilder 不是。因此,在单线程环境中,使用 StringBuilder 性能更高,而在多线程环境中,StringBuffer 更安全。

🦆
在 Java 中,什么时候使用不可变对象比较合适?

在多线程编程中,不可变对象非常适合,因为它们天然是线程安全的。此外,在使用哈希表作为数据结构时,不可变对象也是一个好选择,因为它们的哈希码在整个生命周期中不会改变。