【String专题】
[1] String为什么设计成final的?
String 类和其存储数据的成员变量 value 字节数组都是 final 修饰的,final 修饰类则此类不可被继承,修饰数组则数组不可变。这是为了保证它的线程安全。
[2] String 是不可变类为什么值可以修改?
对一个 String 对象的任何修改实际上都是创建一个新 String 对象,再引用该对象。只是修改 String 变量引用的对象,没有修改原 String 对象的内容。
[3] 字符串拼接的方式有哪些?
-
直接用
+
,底层用 StringBuilder 实现。只适用小数量,如果在循环中使用+
拼接,相当于不断创建新的 StringBuilder 对象再转换成 String 对象,效率极差。 -
使用 String 的 concat 方法,该方法中使用
Arrays.copyOf
创建一个新的字符数组 buf 并将当前字符串 value 数组的值拷贝到 buf 中,buf 长度 = 当前字符串长度 + 拼接字符串长度。之后调用getChars
方法使用System.arraycopy
将拼接字符串的值也拷贝到 buf 数组,最后用 buf 作为构造参数 new 一个新的 String 对象返回。效率稍高于直接使用+
。 -
使用 StringBuilder 或 StringBuffer,两者的
append
方法都继承自 AbstractStringBuilder,该方法首先使用Arrays.copyOf
确定新的字符数组容量,再调用getChars
方法使用System.arraycopy
将新的值追加到数组中。StringBuilder 是 JDK5 引入的,效率高但线程不安全。StringBuffer 使用 synchronized 保证线程安全。
[4] String a = “a” + new String(“b”) 创建了几个对象?
常量和常量拼接仍是常量,结果在常量池,只要有变量参与拼接结果就是变量,存在堆。
使用字面量时只创建一个常量池中的常量,使用 new 时如果常量池中没有该值就会在常量池中新创建,再在堆中创建一个对象引用常量池中常量。因此 String a = "a" + new String("b")
会创建四个对象,常量池中的 a 和 b,堆中的 b 和堆中的 ab。
[5] String、StringBuilder、StringBuffer的区别?
String:不可变,故线程不安全
StringBuilder:可变,线程不安全
StringBuffer:可变,内部使用 synchronized 进行同步,线程安全