上一篇地址:整理好了!2024年最常见 100 道 Java基础面试题(二十六)-CSDN博客
五十三、String 是可变的吗?为什么?
在Java中,String
类的对象是不可变的(Immutable)。这意味着一旦一个 String
对象被创建,它所包含的字符序列就不能被改变。这个特性是由 String
类的设计决定的,有以下几个原因和考量:
-
安全性:不可变的对象通常是线程安全的,不需要额外的同步措施就可以在多线程环境中安全使用。
-
简单性:不可变的对象简化了程序的逻辑,因为它们的状态不会改变,这使得理解和预测程序行为变得更容易。
-
性能:由于
String
对象是不可变的,相同的字符串字面量可以被多个String
对象共享。Java 虚拟机内部有一个字符串常量池(String Pool),用于存储字符串常量,这有助于节省内存空间。 -
哈希码缓存:因为
String
对象的哈希值在对象创建后不会改变,所以String
类可以安全地在hashCode()
方法中缓存哈希值。这对于使用String
作为哈希表的键(如在HashMap
或HashSet
中)非常有利。
示例
考虑以下代码:
String str = "Hello";
str = str + " World!";
在这个例子中,第一行创建了一个 String
对象,包含内容 "Hello"。第二行看起来像是在修改原有的 String
对象,但实际上,它创建了一个新的 String
对象,包含内容 "Hello World!"。原始对象 "Hello" 仍然存在于字符串常量池中,没有被修改。
注意事项
- 尽管
String
对象本身不可变,但String
类提供了一些看起来像是修改字符串的方法,如replace()
、substring()
等。这些方法实际上返回了一个新的String
对象,而不是修改原始对象。
总结
String
类的对象在Java中是不可变的,这是由于其设计决策,旨在提高安全性、简单性、性能,并允许哈希码缓存。理解 String
的不可变性对于编写高效的字符串处理程序和利用Java的字符串常量池非常重要。当需要修改字符串时,应使用 StringBuilder
或 StringBuffer
类,这些类提供了可变的字符串对象。
五十四、String 类可以被继承吗?
在Java中,String
类是final
的,这意味着它不能被继承。final
关键字在类名前面声明,指示该类不能有子类。Java设计者将String
类定义为final
,主要是基于以下几个原因:
-
安全性:
String
类在Java中扮演着重要的角色,它是许多其他类和库的基础。由于String
是不可变的,它的安全性和稳定性得到了保证。允许继承可能会破坏这些属性。 -
性能:
String
对象经常用于哈希映射(如HashMap
)的键。不可变的String
对象可以安全地用作哈希表的键,因为它们的哈希码在创建后不会改变。如果String
可以被继承并改变,那么它作为哈希表键的效率和可靠性将受到影响。 -
字符串常量池:Java虚拟机内部使用字符串常量池来存储字符串常量。如果
String
可以被继承,那么子类对象的字符串值可能会在运行时改变,这将使得字符串常量池的实现变得复杂。 -
内部实现:
String
类的内部实现是经过优化的,以提高性能和减少内存使用。允许继承可能会引入无法预料的复杂性和性能问题。 -
设计哲学:Java 的设计哲学倾向于使用组合而不是继承来实现代码的复用和扩展。继承
String
并不会带来明显的好处,反而可能会引入问题。
示例
尝试继承String
类将导致编译错误:
public class MyString extends String {
// ...
}
上面的代码将无法编译,因为String
是final
的。
注意事项
- 尽管不能继承
String
,但可以通过实现自定义的toString()
方法来提供对象的字符串表示形式。 - 如果需要一个可变的字符串类,可以使用
StringBuilder
或StringBuffer
。
总结
String
类在Java中被明确设计为final
,不能被继承。这是为了保持其安全性、性能和内部实现的简洁性。理解String
的不可变性和final
状态对于编写健壮的Java程序非常重要。当需要可变字符串时,应使用StringBuilder
或StringBuffer
。