我们用图的形式以更加形象地解释Java String的不变性
1. 声明一个字符串
String s = "abcd";
2. 将一个字符串变量赋给另一个字符串变量
String s2 = s;
3. 字符串拼接
s = s.concat("ef");
总结
从上面的3个图中,我们看到,当字符串string在内存(heap)中创建后,就不会再改变,所以对该字符串进行的所有改变操作实际上都没有改变原来的字符串,而是生成了一个新的字符串,这就是所谓的Java String的不变性(immutability)。
每一次的修改操作都会生成一个新的字符串,慢慢地消耗了内存,对GC来说也是非常费时的一件事,这样显然效率非常低,所以如果我们需要多次改变创建的字符串的话该怎么办呢?这时候StringBuffer和StringBuilder隆重登场了。下面举个StringBuilder的例子:
下面的代码展示的是如何将读入的文件内容转换为字符串
public static String readFileToString() throws IOException {
File dirs = new File(".");
String filePath = dirs.getCanonicalPath() + File.separator+"src"+File.separator+"TestRead.java";
StringBuilder fileData = new StringBuilder(1000);//Constructs a string buffer with no characters in it and the specified initial capacity
BufferedReader reader = new BufferedReader(new FileReader(filePath));
char[] buf = new char[1024];
int numRead = 0;
while ((numRead = reader.read(buf)) != -1) {
String readData = String.valueOf(buf, 0, numRead);
fileData.append(readData);
buf = new char[1024];
}
reader.close();
String returnStr = fileData.toString();
System.out.println(returnStr);
return returnStr;
}
关键之处就是,每次读入的内容生成字符串readData,然后使用append方法将该字符串拼接到StringBuilder类型的fileData上。
StringBuffer和StringBuilder非常相似,且都是可变的(mutable)字符串,那么两者有什么不同呢?简单地说就是StringBuffer是多线程安全的(什么是多线程安全?自己百度去),那么为什么还用StringBuilder呢?原因在于StringBuilder不需要考虑多线程问题,所以速度更快。因此通常在多线程对String进行操作的情况下才会使用到StringBuffer。
而从编程使用角度来看,String、StringBuffer、StringBuilder其实都是字符串。