String
String类是不可变类,即一旦一个String对象被创建以后,包含在这个对象中的字符序列是不可改变的,直至这个对象被销毁。
这个是String类的解释,之前童鞋看到这个情况,不能理解上述的解释,如下
String a = "123"; a = "456"; // 打印出来的a为456 System.out.println(a)
看到这里,不明白了,这不是明明已经对他进行修改了吗?为什么还说他是一个不可变类呢?
经过和小伙伴们的学习,明白String类不可变在哪里体现出来的,接下来就看一张上述a对象的内存存储空间图
可以看出来,再次给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对象的内存空间图:
所以说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类中实现的方法:
StringBuilder类中实现的方法:
由此可见,StringBuffer类中的方法都添加了synchronized关键字,也就是给这个方法添加了一个锁,用来保证线程安全。
Java9的改进
Java9改进了字符串(包括String、StringBuffer、StringBuilder)的实现。在Java9以前字符串采用char[]数组来保存字符,因此字符串的每个字符占2字节;而Java9的字符串采用byte[]数组再加一个encoding-flag字段来保存字符,因此字符串的每个字符只占1字节。所以Java9的字符串更加节省空间,字符串的功能方法也没有受到影响
参考链接:https://blog.csdn.net/csxypr/article/details/92378336