解析Java中的String、StringBuilder、StringBuffer类(一)
引言
String 类及其相关的StringBuilder、StringBuffer 类在 Java 中的使用相当的多,在各个公司的面试中也是必不可少的。因此,在本周,我打算花费一些时间来认真的研读一下 String、StringBuilder、StringBuffer类 的相关代码。
String的不可变性
这个特性是 String 相当重要的一个特性,为了深入理解,我直接贴上其源代码
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;
}
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
.....
通过以上几个方法的代码,我们可以得出以下的结论:
- String 对象时不可变的。所谓不可变的意思是说我们使用的很多方法来对字符串进行修改,如以下所示:
public static void main(String[] args) {
String str = "test";
str = str + "a";
System.out.println(str);//testa
str += "b";
System.out.println(str);//testab
}
诸如上面的 + 号和 concat, replace 等看起来会改变 String 值的方法,其最终都是创建了一个全新的 String 对象,用来包含修改后的字符串内容。str 最先指向的对象 "test" 一直呆在原物理位置上。各个方法操作的其实是复制的一份引用,返回的是一个新的对象,以上例子的原 "test" 还在原始处。
一些误区:String 的不可变性并不是因为下面的语句
private final char value[];
final 在引用类型中,只是确保了不能指向其它引用,而不能确保引用的更改。value 是 private 的, 虽然 String 没有提供更改value的方法,但通过反射可将其更改。
String的 + 与 += 符号
众所周知, C++ 是可以重载操作符的, 但 Java 并不允许程序员对操作符进行重载,而String的 + 与 += 符号却违反了这个规则。我们都知道,Java 中的这两个操作符都是对字符串进行拼接,看一下以下的代码:
class Test{
public static void main(String[] args){
String str = "a";
str +="hello" + "world" + "!";
System.out.println(str);//ahelloworld!
String pStr = "a" + str + "b";
System.out.println(pStr);//aahelloworld!b
}
}
如符按照我们理解的 String 的不可变性,那么在多次进行 + 操作时,应该会在最终的结果之前生成多个中间的文件,那么事实真的是这样子吗?如果是这样子想一下就知道效率和性能有多糟糕了。我们对代码进行反编译。
javap -c Test
其产生了如下的 JVM 字节码:
我们可以看到,在以上的代码中, 编译器为我们自动的引入了 java.lang.StringBuilder 类, 并使用了该类的 append(String str) 这个方法, 最终使用 toString() 产生 String 字符串并进行了赋值。
「循环」中拼接字符串不要使用 String
那么,我们是不是可以愉快的使用 + 和 += 这两个操作符了呢? NO! 编译器所能做的也是有限的。
public class Test {
public static void main(String[] args) {
String s = "";
long start = System.currentTimeMillis();
for (int i = 0; i <100000 ; i++) {
s += "a";
}
long end = System.currentTimeMillis();
System.out.println("String time:"+ (end - start));
StringBuilder sb = new StringBuilder("");
long start2 = System.currentTimeMillis();
for (int i = 0; i <100000 ; i++) {
sb.append("a");
}
long end2 = System.currentTimeMillis();
System.out.println("StringBuilder time:"+ (end2 - start2));
}
}
在以上的代码中, 输出是这样子的, 我还去掉了中间装载类所花费的时间:
String time:2573
StringBuilder time:5
为什么差距这么大呢?
同样的,我们对这个文件进行反编译,第一个循环的字节码如下:
可以看出 10 到 40 就是我们的循环体了,在该循环体中,有一个 new 的操作,这意味着每次进行循环时,都会创建一个 StringBuilder 的对象,每次都使用一次 toString() 方法。而这些过程都是相当的影响性能的。
而第二个循环的字节码如下:
从以上我们可以看出,循环是从 95 到 113 行,而这个过程中,始终只有一个 StringBuilder 的对象, 也就是说它没有产生新的对象, 可想而知两个之间的性能是怎么产生差异的了。
因此,「循环」中拼接字符串不要使用 String, 这个在写 toString() 方法时可能会遇到。
好,今天我们就分析到这里,下篇文章再会。
另,转载请注明出处。
解析Java中的String、StringBuilder、StringBuffer类(一)的更多相关文章
- Java基础学习总结(65)——Java中的String,StringBuilder和StringBuffer比较
字符串,就是一系列字符的集合. Java里面提供了String,StringBuffer和StringBuilder三个类来封装字符串,其中StringBuilder类是到jdk 1.5才新增的.字符 ...
- Java中的String、StringBuffer和StringBuilder
作为作为一个已经入了门的java程序猿,肯定对Java中的String.StringBuffer和StringBuilder都略有耳闻了,尤其是String 肯定是经常用的.但肯定你有一点很好奇,为什 ...
- 浅谈java中的String、StringBuffer、StringBuilder类的区别以及关系
在java中最常见的使用就是对字符串的操作:首先先说一下对字符串的理解:字符串就是一连串字符序列,Java提供了String和StringBuffer两个类来封装字符串,并提供一系列方法来操作字符串对 ...
- Java中的String、StringBuffer以及StringBuilder的用法和区别
String String的构造方式有n种(据说n==11),常见的例举一二: String s1 = "hello world"; String s2 = new String( ...
- Java中的String和StringBuffer
在任何编程语言中,字符串都是我们编写程序时不可避免要用到的常用的数据类型之一. 对于Java初学者而言,当谈到String和StringBuffer的区别时,通常都会有些困惑. 而要弄清楚两者之间的区 ...
- Java中的String、StringBuffer、StringBuilder区别以及Java之StringUtils的用法
1.String.StringBuffer.StringBuilder的区别 String是Java中基础类型,是immutable类(不可变)的典型实现,利用string进行拼接是会产生过多无用对象 ...
- Java中的String,StringBuffer,StringBuilder详解与区别
1.String Java中string类是不可变的,其中在声明的源代码中用的final,所以只能声明一次.所以每次在明面上的改变其实是重新生成一个String对象,指针指向新的String对象.同时 ...
- Java中的String、StringBuffer和StringBuilder的区别
类型 是否可变 线程安全 能否频繁修改 String 不可变 安全 否 StringBuffer 可变 安全 能 StringBuilder 可变 不安全 能 1.可变与 ...
- 深刻理解Java中的String、StringBuffer和StringBuilder的差别
声明:本博客为原创博客,未经同意.不得转载!小伙伴们假设是在别的地方看到的话,建议还是来csdn上看吧(链接为http://blog.csdn.net/bettarwang/article/detai ...
随机推荐
- MySQL系统临时表、用户临时表
MySQL临时表分为系统使用的临时表和用户使用的临时表. 系统使用的临时表是指MySQL在执行某些SQL语句时需要依赖临时表来完成整个过程.系统使用的临时表的情况可以分为以下几种: * group ...
- 关于字符型char变量
写程序时,意外发现个很不容易察觉问题出在哪的问题的 scanf("%c",&ch); scanf("%c",&c); printf(" ...
- mysql 在一个实例运行情况下再搭建一个实例
配置mysql服务 详细步骤,请参考(http://study.lishiming.net/chapter17.html#mysql), 阿铭只把简单步骤写一下. 根据阿铭提供的地址,假如你已经搭建好 ...
- Go学习笔记01-语言
1.1 变量 Go 是静态类型语言,不能在运行期改变变量类型.使用关键字 var 定义变量,自动初始化为零值.如果提供初始化值,可省略变量类型,由编译器自动推断. var x int var f fl ...
- angular+require前端项目架构搭建
app //应用入口 directive //自定义指令 require-main //require的主配置文件 存放公共调用的js service //请求后端数据公有类 controllers ...
- prop&attr区别和用法,以多选框为例
1.比较 相同点 : prop和attr作为jquery的方法都可以获取属性值; 不同点 : (1) 对于HTML元素本身就带有的固有属性,使用prop方法, attr获取checkbox的check ...
- vim学习、各类插件配置与安装
vim学习.各类插件配置与安装 vim 插件 配置 1. vim学习 vim基础学习:根据网上流行基础文章<简明Vim练级攻略>,进阶书籍<vim实用技巧>.注:进阶书籍可以在 ...
- puppeteer,新款headless chrome!
puppeteer puppeteer是一种谷歌开发的Headless Chrome,因为puppeteer的出现,业内许多自动化测试库停止维护,比如PhantomJS,Selenium IDE fo ...
- Yii2框架ACF(AccessControl Filter)的使用
AccessControl其实也就是 yii\filters\AccessControl Filter, 我们下面简写为 ACF 作为描述. ACF,访问控制过滤器,适用于简单的验证,面对的对象便是控 ...
- Node.js入门(含NVM、NPM、NVM的安装)
本文最初发表于博客园,并在GitHub上持续更新前端的系列文章.欢迎在GitHub上关注我,一起入门和进阶前端. 以下是正文. Node.js的介绍 引擎 引擎的特性: JS的内核即引擎.因为引擎有以 ...