java基础解析系列(一)---String、StringBuffer、StringBuilder

前言:本系列的主题是平时容易疏忽的知识点,只有基础扎实,在编码的时候才能更注重规范和性能,在出现bug的时候,才能处理更加从容。

我的博客目录

String

==问题

        String s6=new String("jiajun");
String s1="jiajun";
String s2="jiajun";
System.out.println(s1==s2);//true
System.out.println(s1==s6);//false
  • 看常量池中是否已有此字符串,如果有,将指针指向这个字符串
  • 如果使用new来创建字符串对象,那么这个字符串是存放在堆中,无论堆中是否已有这个对象

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);
}
  • 从源码可以看出,任何操作都是创建一个新的对象,不影响原对象

StringBuffer和StringBuidler

初始容量

  • StringBuilder和StringBuffer的构造参数来初始化容量
public StringBuilder() {
super(16);
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
  • 默认情况下容量为16
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
public static char[] copyOf(char[] original, int newLength) {
char[] copy = new char[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
  • 从源码看出,在执行append方法的时候,会执行ensureCapacityInternal方法来保证容量,而如果超出容量的话,会重新创建一个char数组,并将旧的字符数组复制到新的字符数组

线程安全

public synchronized StringBuffer append(StringBuffer sb) {
toStringCache = null;
super.append(sb);
return this;
}
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
 public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
}
public StringBuilder append(String str) {
super.append(str);
return this;
}
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
  • 可以看出,String的方法是加了synchronzied,也就加了锁,那么而在单线程的情况下或者不用考虑线程安全的情况下,那么StringBuilder的性能是更高的

toString方法

 public synchronized String toString() {
if (toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
}
return new String(toStringCache, true);
}
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
  • 通过源码发现,toString方法会创建一个新的String对象

性能试验

间接相加和直接相加

public class d {
public static void main(String[] args) {
String s="I"+"love"+"jiajun";
String s1="I";
String s2="love";
String s3="jiajun";
String s4=s1+s2+s3;
}
}

  • 通过反编译的结果可以看出,第一种方式字符串直接相加,在编译器就直接优化了”Ilovejiajun“
  • 而第二种方式间接相加,从结果可以看出,是先创建一个StringBuilder,然后再apend,最后再toString方法,可以发现性能比第一种低
public class d {
public static void main(String[] args) {
String s="I"+"love"+"jiajun";
String s1="I";
String s2=s1+"lovejiajun";
System.out.println(s==s2);
}
}

  • 同样从反编译的结果可以看出,第二种方式并没有被优化,也是通过StringBuilder来实现的,最后通过toString方法创建一个String对象,所以返回的false
  • 但是当s1是用final修饰的却是不一样的,虚拟机会对其进行优化,所以不会像之前一样创建一个StringBuilder,最后在堆中产生一个对象
public class d {
public static void main(String[] args) { final String s1="I"; String s2=s1+"lovejiajun";
String s3="Ilovejiajun";
//s1==s3
}
}

用+和用append

public class Demo3 {
public static void main(String[] args) {
run1();
run2();
} public static void run1() {
long start = System.currentTimeMillis();
String result = "";
for (int i = 0; i < 10000; i++) {
result += i;
}
System.out.println(System.currentTimeMillis() - start);
} public static void run2() {
long start = System.currentTimeMillis();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 10000; i++) {
builder.append(i);
}
System.out.println(System.currentTimeMillis() - start);
}
//输出:223 1
  • 从实验发现,用append效率更高,从实验一发现,当字符串相加的时候,实际上每次都会重新初始化StringBuilder然后执行相加,这样效率并不高

初始化容量

public class Demo3 {
public static void main(String[] args) {
test1();
test2();
} public static void test1() {
StringBuilder sb = new StringBuilder(7000000);
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
sb.append("jiajun");
}
long end=System.currentTimeMillis()-start;
System.out.println(end);
} public static void test2() { StringBuilder sb = new StringBuilder();
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
sb.append("jiajun");
}
long end=System.currentTimeMillis()-start;
System.out.println(end);
}
//输出:18 26
}
  • 通过实验可以看出,适当的初始化容量可以提高性能,因为当不初始化容量的时候,如果此时append超出容量,那么将会从新创建一个char数组,并且进行复制

总结

  • 用new创建对象的时候,会在堆中创建对象,而如果是直接用引号形式的话,会先看常量池是否有此字符串,有的话指向常量池的字符串
  • StringBuilder是非线程安全的,StringBuffer是线程安全的
  • 使用StringBuilder和StringBuffer的时候最好初始化一个合适的容量,因为如果默认容量不够的话,会重新创建一个char数组,再进行复制
  • 字符串相加的时候,直接相加的时候,编译器会进行优化,而如果是间接相加的时候,实际上会创建一个StringBuilder来进行append

我觉得分享是一种精神,分享是我的乐趣所在,不是说我觉得我讲得一定是对的,我讲得可能很多是不对的,但是我希望我讲的东西是我人生的体验和思考,是给很多人反思,也许给你一秒钟、半秒钟,哪怕说一句话有点道理,引发自己内心的感触,这就是我最大的价值。(这是我喜欢的一句话,也是我写博客的初衷)

作者:jiajun 出处: http://www.cnblogs.com/-new/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。如果觉得还有帮助的话,可以点一下右下角的【推荐】,希望能够持续的为大家带来好的技术文章!想跟我一起进步么?那就【关注】我吧。

java基础解析系列(一)---String、StringBuffer、StringBuilder的更多相关文章

  1. java基础解析系列(九)---String不可变性分析

    java基础解析系列(九)---String不可变性分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---In ...

  2. java基础解析系列(四)---LinkedHashMap的原理及LRU算法的实现

    java基础解析系列(四)---LinkedHashMap的原理及LRU算法的实现 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析 ...

  3. java基础解析系列(五)---HashMap并发下的问题以及HashTable和CurrentHashMap的区别

    java基础解析系列(五)---HashMap并发下的问题以及HashTable和CurrentHashMap的区别 目录 java基础解析系列(一)---String.StringBuffer.St ...

  4. java基础解析系列(六)---深入注解原理及使用

    java基础解析系列(六)---注解原理及使用 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---Integer ja ...

  5. java基础解析系列(七)---ThreadLocal原理分析

    java基础解析系列(七)---ThreadLocal原理分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)-- ...

  6. java基础解析系列(八)---fail-fast机制及CopyOnWriteArrayList的原理

    fail-fast机制及CopyOnWriteArrayList的原理 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列( ...

  7. java基础解析系列(十)---ArrayList和LinkedList源码及使用分析

    java基础解析系列(十)---ArrayList和LinkedList源码及使用分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder jav ...

  8. java基础解析系列(十一)---equals、==和hashcode方法

    java基础解析系列(十一)---equals.==和hashcode方法 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系 ...

  9. java基础解析系列(二)---Integer

    java基础解析系列(二)---Integer 前言:本系列的主题是平时容易疏忽的知识点,只有基础扎实,在编码的时候才能更注重规范和性能,在出现bug的时候,才能处理更加从容. 目录 java基础解析 ...

随机推荐

  1. 大杂烩 -- Iterator 和 Iterable 区别和联系

    基础大杂烩 -- 目录 用Iterator模式实现遍历集合  Iterator模式是用于遍历集合类的标准访问方法.它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构. 例 ...

  2. json_encode让URL内容斜杠/不转义

    同事在开发接口的时候根据接口提示要求传参一个字符串json,该json格式中有URL数组,按照json_encode编码后总发现 http://变成了 http:\/\/  .URL的斜杠自动的被转义 ...

  3. iOS Ad hoc

    There's one situation in which you need an Ad Hoc profile, and that's when you want to test Push Not ...

  4. Docker应用之仓库

    仓库是存放镜像的地方 注册服务器是管理仓库的具体服务器,每个服务器上可以有多个仓库,每个仓库也可以有多个镜像 如 dl.dockerpool.com/ubuntu ,dl.dockerpool.com ...

  5. Hashtable的应用

    一,哈希表(Hashtable)简述 在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似key/value的键值对,其 ...

  6. AESDK开发之UI消息响应

    UI创建: 在该入口下 case PF_Cmd_PARAMS_SETUP: //.... break; 必须在末尾指定UI数目,UI数目一般是枚举,如果和枚举长度不一致也会报错.所以最好是直接修改枚举 ...

  7. 一个汉字转拼音的php类

    代码来自网上,可用 <?php function Pinyin($_String, $_Code='gb2312') { $_DataKey = "a|ai|an|ang|ao|ba| ...

  8. IOS 第三方支付的使用:支付宝

     本文转载至 http://blog.csdn.net/u014011807/article/details/47726799 总结一下支付宝iOS使用步骤: 1 第三方支付:支付宝 使用过程: 1. ...

  9. JSPatch实现原理详解<二>

    本文转载至 http://blog.cnbang.net/tech/2855/ 距离上次写的<JSPatch实现原理详解>有一个月的时间,在这段时间里 JSPatch 在不断地完善和改进, ...

  10. iOS - UITextView在调用textViewDidChange方法,九宫格相关中文输入的问题

    问题一 iOS textView在调用 UITextViewDelegate 的 textViewDidChange方法,九宫格相关中文输入的问题 有时候,需要在textViewDidChange处理 ...