一篇不一样的StringBuffer和StringBuilder
来源:互联网 发布:网络十大恐怖图片 编辑:程序博客网 时间:2024/05/22 08:07
StringBuffer和StringBuilder相信大家都不陌生,我与它们之间也有过一段不愉快的经历。在一次面试过程中,面试官先是问了我的兴趣爱好,虽然我平时喜欢看书,音乐,踢球,跑步等等。但是那段时间为了面试没日没夜的看书,刷资料。当他问到我兴趣爱好时,脑子一片空白、答曰:“看书”。然后迎来的却是面试官的一阵嘲笑和质疑,我当时就已经很不舒服了,喜欢看书很奇怪吗?我本来就是一个转行生,不看书不学习,我拿什么支撑这一份工作?更何况我有过一次考研失败的经历,结果虽然不好,但是过程却培养了我能够静坐下来看一整天书的耐心。
开始技术问题面试后,我更是一脸懵逼,在我明明正确回答了StringBuffer和StringBuilder的区别、HashMap和HashTable的区别几个问题后,面试官再次表示质疑,他认为我说反了。这让我脑子一片混乱,临走时面试官还让我自己回去查。我还用回家查吗?我出了公司门就掏出手机,打开印象笔记,确认了的确是面试官自己弄混淆了。所以,我当时就萌生了要写一篇关于这两个问题的博客的想法。查阅资料,跑Demo,从源码角度去分析,真正的掌握它们。当下一次面试再遇到诸如此类问题时,不再仅仅从表面去回答,不再背出面经中的答案,而是自信得讲出自己的理解。
下面我将从:浅析区别,性能、部分源码解读,历史原因及选用。三个方面试图完整的解读StringBuffer和StringBuilder。希望读者看后既能游刃有余于面试题中,又能对日常开发提供一些支撑。
1.浅析区别
在进入本文主题之前,先提一下String。因为很多面试官会连带一起问,而涉及该问的String部分又比较简单,便一并讲述清楚,也有助于整体理解字符串储存这部分知识。
- String
String可以用来保存字符串,一旦生成一个String对象之后,对其的任何改变操作,都会造成新的字符串生成。因此,当频繁操作(改变)String对象的时候,就会产生大量的垃圾对象。不仅导致不必要的内存消耗,当达到一定内存占用之后,就会引起JVM的GC操作,GC属于耗时操作,必然带来系统性能上的急剧下滑。
- StringBuffer
StringBuffer也可以用来保存字符串,并且它的目的就是为了解决String类对象保存字符串时的尴尬处境。当我们对StringBuffer对象操作并改变时,它不会像String那样产生新的对象,而是对StringBuffer对象本身进行操作甚至改变。
StringBuffer上的主要操作是append和insert方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而insert方法则在指定的点添加字符。
除此之外,由于StringBuffer类中又大量的synchronize修饰,它是一个线程安全的类。(牵涉到更多线程安全的问题将在第三部分详细讲述)
- StringBuilder
在jdk1.5之后,Java又新增了一个StringBuilder类,它是作为StringBuffer的建议替换出现的,它们兼容同一套API。但是StringBuilder不再有大量的synchronize修饰,因此它是非线程安全的。亦因此在实际运行中,不再存在由同步引起的额外开销,从而带来性能上的又一些提升。
2.性能、源码剖析
先简单看下为什么String保存的对象被修改时会产生新的对象。
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0
从源码的开始部分可以看出,String是一个被final修饰的类,它是不能被继承的。虽然被final修饰的类,其中的属性和方法可以选择性的由final修饰与否。而String中字符串的保存是由字符数组来完成的,这个字符数组value恰好也由final修饰。我们知道,数组本身是属于引用变量类型,当final修饰引用类型变量后,它的指针是不可以更改的。所以String对象一旦生成并且有了指针指向,那么它是不可更改的。
有下列部分源码可知,当我们对String对象进行操作,试图更改它,无论是sub、concat还是replace都不是在原有的字符串上进行的,而是重新生成一个新的字符串对象。也就是说,对String对象的任何改变都不影响到原对象。
public String substring(int beginIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } int subLen = value.length - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } return (beginIndex == 0) ? this : new String(value, beginIndex, subLen); }
public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } int len = value.length; char buf[] = Arrays.copyOf(value, len + otherLen); str.getChars(buf, len); return new String(buf, true); }
public String replace(char oldChar, char newChar) { if (oldChar != newChar) { int len = value.length; int i = -1; char[] val = value; /* avoid getfield opcode */ while (++i < len) { if (val[i] == oldChar) { break; } } if (i < len) { char buf[] = new char[len]; for (int j = 0; j < i; j++) { buf[j] = val[j]; } while (i < len) { char c = val[i]; buf[i] = (c == oldChar) ? newChar : c; i++; } return new String(buf, true); } } return this; }
可以看到,这三个方法的返回值都是new了一个String对象。当然,他们调用的String构造方法各不相同。
例如,concat方法就是在新声明的字符数组NC拷贝了原String对象内的字符数组之后,再将(增添)目标String对象中的字符数组OC拼接在NC之后,最后调用如下构造方法,并传入NC。
String(char[] value, boolean share) { // assert share : "unshared not supported"; this.value = value; }
关于这部分,如果想全面了解请自行阅读源码。
…由于在写博客的时候又冒出几个问题,我都还没弄懂。稍后接着写。
- 一篇不一样的StringBuffer和StringBuilder
- stringbuffer 和stringbuilder的区别
- Stringbuffer和StringBuilder的区别
- StringBuffer 和 StringBuilder 的区别
- StringBuffer和StringBuilder的区别
- StringBuilder和StringBuffer的区别
- StringBuilder和StringBuffer的用处
- StringBuilder和StringBuffer的区别
- StringBuffer 和 StringBuilder 的区别
- stringBuffer和stringBuilder的区别
- StringBuffer和Stringbuilder的区别
- StringBuilder和StringBuffer的区别
- StringBuffer和StringBuilder的区别
- StringBuilder和StringBuffer的区别
- StringBuffer和StringBuilder的区别
- StringBuffer 和 StringBuilder的区别
- StringBuffer和StringBuilder的区别
- StringBuilder和StringBuffer的区别
- python 排序算法之 二分查找
- java中对象和对象的引用的区别
- Servlet中获取资源
- iOS KVO的优势及缺点
- [MongoDB] Mongodb的初应用
- 一篇不一样的StringBuffer和StringBuilder
- linux运维故障定位汇总
- Ubuntu安装python3
- Jeecg 重写编辑按钮相关的 js 方法
- Install OpenCV 2.4.9 in Ubuntu 14.04, 13.10(Ubuntu 14.04, 13.10 下安装 OpenCV 2.4.9)
- Oracle数据库的卸载
- 【Android开发点滴】Android Studio常用快捷键
- Bootstrap table 服务器端分页示例
- centos下的mysql-cluster集群安装