加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

从源码了解String,StringBuffer和StringBuuilder

发布时间:2020-12-15 07:56:16 所属栏目:Java 来源:网络整理
导读:1.String (1)类定义 public final class String ??? implements java.io.Serializable,ComparableString,CharSequence String类是个final类,实现了序列化接口,比较大小接口和只读字符序列接口。String和其他八个基本数据类型的包装类共同为不可变类。 (

1.String

(1)类定义


public final class String
??? implements java.io.Serializable,Comparable<String>,CharSequence


String类是个final类,实现了序列化接口,比较大小接口和只读字符序列接口。String和其他八个基本数据类型的包装类共同为不可变类。

(2)主要变量


private final char value[];

String类的底层基本是char类型数组,String的一些基本方法也是调用char数组的基本方法。

(3)主要构造方法

public String() {
  this.value = "".value;
}

String的默认值为"";

(4)String常量池

jvm在启动时就会加载的一块空间,符串常量池的特点就是有且只有一份相同的字面量,如果有其它相同的字面量,jvm则返回这个字面量的引用,如果没有相同的字面量,则在字符串常量池创建这个字面量并返回它的引用。通过使用new关键字得对象会放在堆里,而不会加载到字符串常量池,intern()方法能使一个位于堆中的字符串在运行期间动态地加入到字符串常量池中。

(5)字符串拼接

String字符串拼接一般通过用+号实现,正常情况下有两种形式:

String a = "ab" + "cd";


此时在JVM在编译时就认为这个加号是没有用处的,编译的时候就直接变成abcd,即使是后面添加多个字符串效率不会比StringBuiler或者StringBuffer慢。

String a = "ab";
String b = "cd";
String c = a + b;

此时字符串拼接系统会优化成通过new StringBuiler,进行两次append操作,该操作是在堆中进行,如果是进行多次拼接,会产生多个StringBuiler对象,效率自然会降低,但是如果是在同一行代码里做拼接操作,只是额外new了一个StringBuiler对象,效率也不会慢。

2.StringBuilder

(1)类定义

public final class StringBuilder extends AbstractStringBuilder 
      implements java.io.Serializable,CharSequence


abstract class AbstractStringBuilder implements Appendable,CharSequence

StringBuilder类是final类,实现了序列化接口,只读字符序列接口,其父类实现了只读字符序列接口和拼接接口,该类是可变类。

(2)主要变量

private final char value[];

StringBuilder的底层基本实现和String是一致的

(3)主要构造方法

public StringBuilder() {
  super(16);
}

AbstractStringBuilder(int capacity) {
  value = new char[capacity];
}

StringBuiler类的基本构造方法是一个容量为16的字符串数组

(4)字符串拼接

public StringBuilder append(String str) {
??? super.append(str);
??? return this;
}


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));
??? }
}

内部的实现是通过char数组操作的,如果超过容量,会发生通过数组拷贝方式的扩容操作。

(5)线程安全性

  从上面的源码解析,count += len;并非原子操作,如果两个线程同时访问到这个方法,那么AbstractStringBuilder中的count是不是就是相同的,所以这两个线程都是在底层char数组的count位置开始append添加,那么最终的结果肯定就是在后执行的那个线程append进去的数据会将前面一个覆盖掉,所以StringBuilder在字符串拼接操作是线程不安全的。由于String的拼接也是通过StringBuiler来实现,所以String的字符拼接也不是线程安全的

3.StringBuffer

(1)类定义

public final class StringBuffer
??? extends AbstractStringBuilder
??? implements java.io.Serializable,CharSequence

StringBuffer其父类实现了只读字符序列接口和拼接接口,与StringBuilder有公共的父类AbstractStringBuilder,该类是可变类。

(2)主要变量
StringBuffer的底层基本实现和StringBuilder是一致的。

(3)构造方法

StringBuffer的构造方法和StringBuilder是一致的。

(4)字符串拼接


public synchronized StringBuffer append(String str) {
??? toStringCache = null;
??? super.append(str);
??? return this;
}

?

StringBuffer字符串拼接基本与StringBuilder内部实现是一致的,主要是区别是在方法体上通过synchronized关键字加锁。

(5)线程安全性

  从上面的源码解析,由于在方法加上synchronize关键字,所以字符串拼接操作是线程安全。

?

备注:在正式面试时,基本回答三者的区别是:String是不可变类,StringBuffer和StringBuilder是可变类;String在多次字符串拼接时效率低,且线程不安全,StringBuilder效率最高,但是线程不安全,StringBuffer效率在前两者其中,但是线程安全。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读