String 为什么是不变的?String 和 StringBuffer、StringBuilder 的区别是什么?final 关键字的总结。

  1. 可变性:
  • String 类中使用 final 关键字字符数组保存字符串,private final char value[],所以 String 对象是不可变的。
  • 而 StringBuilder 和 StringBuffer 都继承自 AbstractStringBuilder 类,在AbstractStringBuilder 中也是使用字符数组保存字符串char[]value但是没有用 final 关键字修饰,所以这两种对象都是可变的。
    StringBuilder 和 StringBuffer 的构造方法都是调用父类的构造方法也就是 AbstractStringBuilder 实现的。

AbstractStringBuilder.java

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    char[] value;
     int count;
     AbstractStringBuilder() {
     }
     AbstractStringBuilder(int capacity) {
     value = new char[capacity];
     }
  1. 线程安全性:
  • String 中的对象是不可变的,也就可以理解为常量,线程安全。
  • AbstractStringBuilder 是 StringBuilder 和 StringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法:
    • StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。
    • StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。
  1. 性能:
  • 每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后指针指向新的 String 对象。
  • StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒出线程不安全的风险。
    对于三者使用的总结
  1. 操作少量的数据 = String
  2. 单线程操作字符串缓冲区下操作大量数据 = StringBuilder
  3. 多线程操作字符串缓冲区下操作大量数据 = StringBuffer

既然提到了final,总结下final
final 关键字主要用在三个方面:变量、方法、类

  1. 对于一个 final 变量,如果是基本数据类型的变量,则其数值一旦在初始化后便不能更改;如果是引用类型变量,则对其初始化之后便不能再让其指向另一个对象。
  2. 当用 final 修饰一个类时,表明这个类不能被继承。final 类中的所有成员方法都会被隐式地指定为 final 方法。
  3. 使用 final 方法的原因有两个:
  • 把方法锁定,以防任何继承类修改它的定义;
  • 效率。在早期的 Java 实现版本中,会将 final 方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的 Java 版本已经不需要使用 final 关键字进行这些优化了)。类中所有的 private 方法都隐式地指定为 final。

你可能感兴趣的:(String 为什么是不变的?String 和 StringBuffer、StringBuilder 的区别是什么?final 关键字的总结。)