String
官方解释: String类是不可变类,即一旦一个String对象被创建以后,包含在这个对象中的字符序列是不可改变的,直至这个对象被销毁。
对string重新赋值,如果字符串常量池不存在这个新的赋值对象,就会创造新的对象,如果存在,就不会创建。
也就是说,当我们String a = “111”;a=“222"时,并没有给原来堆中的实例对象重新赋值,而是生成了一个新的对象,并把a指向"222”,而之前的实例对象"111"依然存在,等待被垃圾回收处理。我们来看一下这张对String操作时内存变化的图:
StringBuffer与StringBuilder
这两者基本相似,都是可变字符串对象,主要区别为线程是否安全。
StringBuilder的具体实现:
new Thread(new Runnable){
@Override
public void run(){
HttpURLConnection connection = null;
BufferedReader reader = null;
try{
URL url = new URL("http://www.baidu.com");
connection = (HttpURLConnection)url.openConnection();
connnection.setRequestMethod("GET");
InputStream in = connection.getInputStream();
//下面对获取到的输入流进行读取
reader= new BufferedReader(new InputStreamReader(in));
StringBuilder response = new(StringBuilder());
String line;
While ((line =reader.readLine())!= null ){
response.append(line));
}
showResponse(reponse.toString())
}
}......
}
继承结构
总结
最后,引用菜鸟教程下的总结以及相关评论:
- String 长度大小不可变,而StringBuffer 和 StringBuilder 长度可变
- StringBuffer 线程安全,而StringBuilder 线程不安全
- StringBuilder 速度快
- stringbuffer 基本没有适用场景,你应该在所有的情况下选择使用 stringbuiler
补充一点,关于线程安全,即使你真的遇到了这样的场景,很不幸的是,恐怕你仍然有 99.99…99% 的情况下没有必要选择 stringbuffer,因为 stringbuffer 的线程安全,仅仅是保证 jvm 不抛出异常顺利的往下执行而已,它可不保证逻辑正确和调用顺序正确。大多数时候,我们需要的不仅仅是线程安全,而是锁。
最后,为什么会有 stringbuffer 的存在,如果真的没有价值,为什么 jdk 会提供这个类?答案太简单了,因为最早是没有 stringbuilder 的,sun 的人不知处于何种愚蠢的考虑,决定让 stringbuffer 是线程安全的,然后大约 10 年之后,人们终于意识到这是一个多么愚蠢的决定,意识到在这 10 年之中这个愚蠢的决定为 java 运行速度慢这样的流言贡献了多大的力量,于是,在 jdk1.5 的时候,终于决定提供一个非线程安全的 stringbuffer 实现,并命名为 stringbuilder。顺便,javac 好像大概也是从这个版本开始,把所有用加号连接的 string 运算都隐式的改写成 stringbuilder,也就是说,从 jdk1.5 开始,用加号拼接字符串已经没有任何性能损失了。
如果没有循环的情况下,单行用加号拼接字符串是没有性能损失的,因为java 编译器会隐式的替换成 stringbuilder。
但在有循环的情况下,编译器没法做到足够智能的替换,会有性能损耗。
因此,用循环拼接字符串的时候,还是老老实实的用 stringbuilder 吧。
附上参照表: