String

  String类是不可变类,即一旦一个String对象被创建以后,包含在这个对象中的字符序列是不可改变的,直至这个对象被销毁。

  这个是String类的解释,之前童鞋看到这个情况,不能理解上述的解释,如下

String a = "123";
a = "456";
// 打印出来的a为456
System.out.println(a)

看到这里,不明白了,这不是明明已经对他进行修改了吗?为什么还说他是一个不可变类呢?

经过和小伙伴们的学习,明白String类不可变在哪里体现出来的,接下来就看一张上述a对象的内存存储空间图

String、StringBuffer和StringBuilder的区别:_java

可以看出来,再次给a赋值时,并不是对原来堆中实例对象进行重新赋值,而是生成一个新的实例对象,并且指向“456”这个字符串,a则指向最新生成的实例对象,之前的实例对象仍然存在,如果没有被再次引用,则会被垃圾回收。

StringBuffer
  StringBuffer对象则代表一个字符序列可变的字符串,当一个StringBuffer被创建以后,通过StringBuffer提供的append()、insert()、reverse()、setCharAt()、setLength()等方法可以改变这个字符串对象的字符序列。一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString()方法将其转换为一个String对象。

StringBuffer b = new StringBuffer("123");
b.append("456");
// b打印结果为:123456
System.out.println(b);

  在看一下b对象的内存空间图:

String、StringBuffer和StringBuilder的区别:_字符串_02

 所以说StringBuffer对象是一个字符序列可变的字符串,它没有重新生成一个对象,而且在原来的对象中可以连接新的字符串。

注意:既然定义字符串可以使用String或者StringBuffer类,那我们如何选择?若在程序中,需要经常增加,删除,或者替换字符串,使用StringBuffer类可以轻松应对。如果只是静态使用字符串,String类是个很好的选择。

扩展:StringBuffer 方法

以下是 StringBuffer 类支持的主要方法:

序号

方法描述

1

public StringBuffer append(String s)
将指定的字符串追加到此字符序列。

注意:append只能在字符串后面追加内容,insert()方法可以将内容插入到字符串任意位置

2

public StringBuffer reverse()

 将此字符序列用其反转形式取代。

3

public delete(int start, int end)
移除此序列的子字符串中的字符。

如果删除指定位置单个字符,deleteCharAt()方法

4

public insert(int offset, int i)

将 ​​int​​ 参数的字符串表示形式插入此序列中。(第二个参数可以是字符串)

5

replace(int start, int end, String str)

使用给定 ​​String​​ 中的字符替换此序列的子字符串中的字符。

下面的列表里的方法和 String 类的方法类似:

 

序号

方法描述

1

int capacity()

返回当前容量。默认容量为16字符

2

char charAt(int index)

返回此序列中指定索引处的 ​​char​​ 值。

3

void ensureCapacity(int minimumCapacity)

确保容量至少等于指定的最小值。

4

void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)

将字符从此序列复制到目标字符数组 ​​dst​​。

5

int indexOf(String str)

返回第一次出现的指定子字符串在该字符串中的索引。

6

int indexOf(String str, int fromIndex)

从指定的索引处开始,返回第一次出现的指定子字符串在该字符串中的索引。

7

int lastIndexOf(String str)

返回最右边出现的指定子字符串在此字符串中的索引。

8

int lastIndexOf(String str, int fromIndex)

返回 String 对象中子字符串最后出现的位置。

9

int length()

 返回长度(字符数)。

10

void setCharAt(int index, char ch)

将给定索引处的字符设置为 ​​ch​​。若超过指定的字符串长度则将其截除

11

void setLength(int newLength)

设置字符序列的长度。

12

CharSequence subSequence(int start, int end)

返回一个新的字符序列,该字符序列是此序列的子序列。

13

String substring(int start)

返回一个新的 ​​String​​,它包含此字符序列当前所包含的字符子序列。

14

String substring(int start, int end)

返回一个新的 ​​String​​,它包含此序列当前所包含的字符子序列。

15

String toString()
返回此序列中数据的字符串表示形式。

注意:StringBuffer类没有重写Object类的equals()方法,所以StringBuffer类不能使用equals()方法比较StringBuffer值,应当使用toString()方法将SringBuffer的内容转换为String字符串,再使用equals()方法比较

提示:(1)StringBuffer的capacity()方法返回的容量和length()方法返回的字符串长度,不止在数值上不同,含义上也不同。

            (2)

StringBuffer类可以创建可修改的字符串序列。该类有StringBuffer(),StringBuffer(int size),StringBuffer(String s)三个改造方法。

1、StringBuffer()的初始容量可以容纳16个字符,当该对象的实体存放的字符的长度大于16时,实体容量就自动增加。StringBuffer对象可以通过length()方法获取实体中存放的字符序列长度,通过capacity()方法来获取当前实体的实际容量。

2、StringBuffer(int size)可以指定分配给该对象的实体的初始容量参数为参数size指定的字符个数。当该对象的实体存放的字符序列的长度大于size个字符时,实体的容量就自动的增加。以便存放所增加的字符。增长规律:(容量+1)*2

3、StringBuffer(String s)可以指定给对象的实体的初始容量为参数字符串s的长度额外再加16个字符。当该对象的实体存放的字符序列长度大于size个字符时,实体的容量自动的增加,以便存放所增加的字符。如果按照增长规律后还是不够

     那么它的容量就等于字符串的长度。(见Java编程手记   欧二强等编著)

StringBuilder
  StringBuilder类也代表可变字符串对象。实际上,StringBuilder和StringBuffer基本相似,两个类的构造器和方法也基本相同。不同的是:StringBuffer是线程安全的,而StringBuilder则没有实现线程安全功能,所以性能略高。

StringBuffer是如何实现线程安全的呢?
StringBuffer类中实现的方法:
String、StringBuffer和StringBuilder的区别:_子字符串_03

 StringBuilder类中实现的方法:

String、StringBuffer和StringBuilder的区别:_字符串_04

由此可见,StringBuffer类中的方法都添加了synchronized关键字,也就是给这个方法添加了一个锁,用来保证线程安全。

Java9的改进
  Java9改进了字符串(包括String、StringBuffer、StringBuilder)的实现。在Java9以前字符串采用char[]数组来保存字符,因此字符串的每个字符占2字节;而Java9的字符串采用byte[]数组再加一个encoding-flag字段来保存字符,因此字符串的每个字符只占1字节。所以Java9的字符串更加节省空间,字符串的功能方法也没有受到影响