final 修饰 StringBuffer 后还可以 append 吗?
参考回答
可以,final
修饰的 StringBuffer
对象仍然可以调用其方法(如 append
)来修改内容。final
的作用是让引用不可变,而不是让对象本身不可变。
也就是说,final
修饰后,引用变量不能被重新赋值,但引用指向的对象内容仍然可以修改。
详细讲解与拓展
1. final
的作用
final
修饰变量的规则是:
- 基本数据类型:变量的值不能被修改。
- 引用数据类型:变量的引用不能被重新赋值,但引用指向的对象内容可以被修改。
示例:
public class TestFinal {
public static void main(String[] args) {
final StringBuffer sb = new StringBuffer("Hello");
sb.append(" World"); // 修改对象内容
System.out.println(sb); // 输出 "Hello World"
// sb = new StringBuffer("New"); // 编译错误,不能重新赋值引用
}
}
解释:
final
修饰sb
,表示sb
引用不能指向新的StringBuffer
对象。- 但
sb
指向的对象内容仍然可以通过其方法(如append
)修改。
2. final
的行为
假设 final
修饰了一个 StringBuffer
对象 sb
:
final StringBuffer sb = new StringBuffer("Hello");
- 可以修改对象内容:
sb.append(" World"); // 修改内容,合法
append
方法会修改sb
指向的StringBuffer
对象的内部状态。 -
不能改变引用:
sb = new StringBuffer("New String"); // 编译错误
这里尝试将
sb
指向另一个新的对象,会引发编译错误。
3. 不可变类(如 String
)的对比
与 String
的不可变性不同,StringBuffer
是一个可变类,它的内容可以在对象被创建后通过方法(如 append
、delete
)进行修改。
以下是两者的区别:
String
:
- 不可变类,每次修改都会创建新对象。
- 即使是
final
修饰的String
,内容仍然无法改变。final String str = "Hello"; str.concat(" World"); // str 内容未改变 System.out.println(str); // 输出 "Hello"
StringBuffer
:
- 可变类,
final
修饰后内容仍然可以修改。final StringBuffer sb = new StringBuffer("Hello"); sb.append(" World"); System.out.println(sb); // 输出 "Hello World"
4. final
与线程安全
final
与引用不可变:- 如果一个对象引用是
final
,则其他线程无法更改这个引用指向的对象。 - 但如果对象本身是可变的(如
StringBuffer
),对象内容仍然可以被多线程修改。
- 如果一个对象引用是
- 线程安全性示例:
public class ThreadTest { public static void main(String[] args) { final StringBuffer sb = new StringBuffer("Hello"); new Thread(() -> sb.append(" World")).start(); new Thread(() -> sb.append(" Java")).start(); System.out.println(sb); // 输出可能为 "Hello World Java" 或其他结果 } }
虽然
sb
的引用是final
,但StringBuffer
是线程不安全的,其内容可以被多个线程同时修改,导致不可预测的结果。
解决方案:如果需要线程安全,可以使用 StringBuffer
的同步方法,或者改用线程安全的 StringBuilder
。
5. final
的应用场景
- 保护引用不可变: 如果一个引用被
final
修饰,则可以确保它始终指向同一个对象。public class Example { private final StringBuffer buffer = new StringBuffer("Immutable Reference"); public StringBuffer getBuffer() { return buffer; } }
- 配合不可变类: 在不可变类中,
final
常用来确保所有字段的值不可变。
6. 拓展知识
- 不可变类的特性
String
是不可变的,而StringBuffer
和StringBuilder
是可变的。- 如果希望一个
StringBuffer
的内容也不可修改,可以通过封装实现。
-
封装不可修改的
StringBuffer
public class ImmutableStringBuffer { private final StringBuffer buffer; public ImmutableStringBuffer(String str) { buffer = new StringBuffer(str); } public String getContent() { return buffer.toString(); } }
-
线程安全与
StringBuffer
StringBuffer
是线程安全的,因为它的方法使用了同步机制。- 但过多的同步会影响性能,因此在单线程环境下推荐使用
StringBuilder
。
7. 总结
final
修饰StringBuffer
后,可以通过其方法(如append
、delete
)修改内容,但无法重新赋值引用。StringBuffer
是可变类,其内容可以被修改;而String
是不可变类,内容不可修改。- 需要注意线程安全问题,
final
只保证引用不可变,不能保证对象内容不变。