【1】String,StringBuffer,StringBuillder的底层结构研究

简介: 一:StringBuffer的底层(1)线程安全的字符串操作类(2)通过synchronized关键字声明同步方法,保证多线程环境下数据安全1 @Override2 public synchronized StringBuffer append(String str) {3 toStringCache = null;4 super.append(str);5 return this;6 }View Code(3)底层存储数据的Char[]数组,初始化时,该数组的长度是16。

一:StringBuffer的底层

(1)线程安全的字符串操作类

(2)通过synchronized关键字声明同步方法,保证多线程环境下数据安全

1 @Override
2     public synchronized StringBuffer append(String str) {
3         toStringCache = null;
4         super.append(str);
5         return this;
6     }
View Code

(3)底层存储数据的Char[]数组,初始化时,该数组的长度是16。如果构造函数有新传入字符转str,则16基础上加str.length.

 1 /**
 2 *无参构造
 3 */
 4 public StringBuffer() {
 5         super(16);
 6 }
 7 
 8 
 9 
10 /**
11 *带参构造
12 */ 
13 public StringBuffer(String str) {
14         super(str.length() + 16);
15         append(str);
16     }
17 
18 /**
19 *初始化char[]数组
20 */
21    AbstractStringBuilder(int capacity) {
22         value = new char[capacity];
23     }
View Code

 (4)添加字符串的过程

-->先检查内部char[]数组是否需要扩容

-->如需要扩容则进行扩容,然后将原来元数据copy到新数组中。

-->再将新添加的元数据加入到新char[]数组中

 1 public AbstractStringBuilder append(String str) {
 2         if (str == null)
 3             return appendNull();
 4         int len = str.length();
 5         //检查char[]数组是否需要扩容,扩容,并将原来的数据copy进去新扩容的数组中
 6         ensureCapacityInternal(count + len);
 7         //将新添加的数据添加到StringBuilder中的char[]数组中,实现字符串的添加
 8         str.getChars(0, len, value, count);
 9         count += len;
10         return this;
11     }
12 
13 
14 /**
15 *元数组char[]的扩容过程
16 */
17     void expandCapacity(int minimumCapacity) {
18         int newCapacity = value.length * 2 + 2;
19         if (newCapacity - minimumCapacity < 0)
20             newCapacity = minimumCapacity;
21         if (newCapacity < 0) {
22             if (minimumCapacity < 0) // overflow
23                 throw new OutOfMemoryError();
24             newCapacity = Integer.MAX_VALUE;
25         }
26         value = Arrays.copyOf(value, newCapacity);
27     }
28 
29 
30 /**
31 *扩容实现
32 */
33    public static char[] copyOf(char[] original, int newLength) {
34         char[] copy = new char[newLength];
35         System.arraycopy(original, 0, copy, 0,
36                          Math.min(original.length, newLength));
37         return copy;
38     }
View Code

 

 

二:StringBuillder的底层

 (1)线程非安全的字符串操作类

 (2)字符串的添加没有加同步处理,涉及到数组扩容,容易产生脏数据,破坏数据正确性

 (3)底层结构和StringBuffer实现基本一样,只是没有做同步处理。

--->StringBuffer和StringBuillder都继承抽象类AbstractStringBuilder,该抽象类实现了字符串操作的方法。

--->StringBuffer和StringBuillder的实现,运用了模板方法的设计模式,将核心数据操作放在父类方法里,子类实现自己的独有特色的功能,涉及核心操作,调用父类方法。

 

三:String的底层

 

String类没有提供用于修改字符串的方法。String类对象为不可变字符串,如字符串string=”HELLO”永远只包含HELLO这几个字母,而不能修改其中任何一个字符。当然可以修改字符串变量string的引用,让它引用另一个字符串。
不可变字符串有一个优点:编译器可以让字符串实现共享。实际上只有字符串常量(使用“ ”声明,存储在字符串常量池中)是共享的,subStrng,+等操作产生的结果不能共享。
比较字符串值是否相等时使用equals()方法,不能使用==,==比较的是字符串的地址是否相同。如果字符串在常量池中,可以使用==比较,因为指向的都是同一个字符串。

直接使用 ” ” 声明的String对象会直接存储在常量池中,(可以实现共享)
1.String str1=”first”;
jvm在运行时先查找常量池中是否有该字符串,如果有则直接返回该字符串的引用给first(实现了字符串 的共享) ;否则先在常量
池中创建该字符串并返回引用。
此时只会在常量池中创建String对象,不会在堆中创建。
2.String str2=new String(“second”);
该代码生成了两个String对象。因为使用了“”会现在常量池中查找是否存在second对象,没有则创建
否则不创建;在常量池创建完成后,由于使用了new,jvm会在堆中创建内容相同的String对象,并将引用
返回给str2.
3.String str3=”what”; String str4=str3+”a nice day”;
运行时,+ 相当于new,所以堆中会有“what a nice day”对象;常量池中会有”what” “a nice day”两个对象,而不会有”what a nice day”对象。

4.三者在执行速度方面的比较:StringBuilder >  StringBuffer  >  String

5.测试类

 1 package com.yeepay.sxf.mianshi.pagkage;
 2 
 3 public class StringBufferAndStringBuillder {
 4 
 5     public static void main(String[] args) {
 6 //        String a="abc";
 7 //        String b=new String(a);
 8 //        //【true】a和b比较的是内容。便利各自的char[]数组进行比较
 9 //        System.out.println("a和b比较==>"+a.equals(b));
10 //        //【false】 a和b比较的是地址。a在常量池中  b在堆内存中
11 //        System.out.println("a和b比较==>"+a==b);
12         
13         test02();
14         
15     }
16     
17     
18     public static void test01(){
19         /**
20          * 你会很惊讶的发现,生成str对象的速度简直太快了,而这个时候StringBuffer居然速度上根本一点都不占优势。其实这是JVM的一个把戏,实际上:
21             String str = “This is only a” + “ simple” + “test”;
22             
23             其实就是:
24             String str = “This is only a simple test”;
25             
26             所以不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的String对象的话,速度就没那么快了,譬如:
27             
28              String str2 = “This is only a”;
29 
30     String str3 = “ simple”;
31 
32     String str4 = “ test”;
33 
34     String str1 = str2 +str3 + str4;
35 
36     这时候JVM会规规矩矩的按照原来的方式去做。
37          */
38     }
39     
40     
41     public static void test02(){
42          //string3指向常量池中的字符串second
43          //string4指向堆中的字符串second
44          //所以值相同,引用不同
45          String string3="second";
46          String string4=new String("second");
47          System.out.println(string3==string4);
48         System.out.println(string3.equals(string4));
49 
50          //string5指向常量池中的字符串third
51          //string6一开始指向堆中的字符串third,但是调用intern()方法之后,且该方法调用时先检查常量池中是否有值为string6
52          //的字符串,如果有则返回该字符串的引用,否则在常量池中创建该字符串,并返回引用
53          //所以一开始引用不相等,后来相等
54          String string5="third";
55          String string6=new String("third");
56          System.out.println(string5==string6);
57          string6=string6.intern();
58          System.out.println(string5==string6);
59     }
60 }
View Code

 

相关文章
|
26天前
|
安全
String、StringBuffer、StringBuilder的区别
String 由 char[] 数组构成,使用了 final 修饰,对 String 进行改变时每次都会新生成一个 String 对象,然后把指针指向新的引用对象。 StringBuffer可变并且线程安全;有一定缓冲区容量,字符串大小没超过容量,不会重新分配新的容量,适合多线程操作字符串; StringBuiler可变并且线程不安全。速度比StringBuffer更快,适合单线程操作字符串。 操作少量字符数据用 String;单线程操作大量数据用 StringBuilder;多线程操作大量数据用 StringBuffer
|
3月前
|
安全 Java
String、StringBuffer、StringBuilder的区别
这篇文章讨论了Java中String、StringBuffer和StringBuilder的区别。String是不可变的,每次操作都会产生新的对象,效率低且浪费内存。StringBuilder可以在原字符串基础上进行操作,不开辟额外内存,弥补了String的缺陷。StringBuffer和StringBuilder类似,但StringBuffer的方法是线程安全的。文章还列举了StringBuffer的常用方法,并提供了使用示例代码。最后总结了这三者的主要区别。
String、StringBuffer、StringBuilder的区别
|
2月前
|
存储 安全 Java
String、StringBuffer 和 StringBuilder 的区别
【10月更文挑战第21天】String、StringBuffer 和 StringBuilder 都有各自的特点和适用场景。了解它们之间的区别,可以帮助我们在编程中更合理地选择和使用这些类,从而提高程序的性能和质量。还可以结合具体的代码示例和实际应用场景,进一步深入分析它们的性能差异和使用技巧,使对它们的理解更加全面和深入。
39 0
|
4月前
|
Java
【Java基础面试二十六】、说一说String和StringBuffer有什么区别
这篇文章区分了Java中的String和StringBuffer类:String是不可变类,一旦创建字符序列就不能改变;而StringBuffer代表可变的字符串,可以通过其方法修改字符序列,最终可以通过`toString()`方法转换为String对象。
【Java基础面试二十六】、说一说String和StringBuffer有什么区别
|
4月前
|
安全 Java API
Java系类 之 String、StringBuffer和StringBuilder类的区别
这篇文章讨论了Java中`String`、`StringBuffer`和`StringBuilder`三个类的区别,其中`String`是不可变的,而`StringBuffer`是线程安全的可变字符串类,`StringBuilder`是非线程安全的可变字符串类,通常在单线程环境下性能更优。
Java系类 之 String、StringBuffer和StringBuilder类的区别
|
4月前
|
安全
String,Stringbuffer,StringBuilder的区别
【8月更文挑战第16天】String,Stringbuffer,StringBuilder的区别
38 2
|
4月前
|
缓存 安全 Java
【揭秘】String vs StringBuilder vs StringBuffer:三大字符串类的秘密较量!你真的知道何时该用哪个吗?
【8月更文挑战第19天】探讨Java中`String`、`StringBuilder`与`StringBuffer`的区别及应用场景。`String`不可变,适合做哈希表键或多线程共享。`StringBuilder`支持动态修改字符串,适用于单线程环境以提高性能。`StringBuffer`与`StringBuilder`功能相似,但线程安全。示例代码展示各类型的基本用法。选择哪种类型取决于具体需求和性能考量。
62 0
|
5月前
|
安全 Java 索引
带你快速掌握Java中的String类和StringBuffer类(详解常用方法 | 区别 )
带你快速掌握Java中的String类和StringBuffer类(详解常用方法 | 区别 )
|
7月前
|
存储 Java
Java基础复习(DayThree):字符串基础与StringBuffer、StringBuilder源码研究
Java基础复习(DayThree):字符串基础与StringBuffer、StringBuilder源码研究
Java基础复习(DayThree):字符串基础与StringBuffer、StringBuilder源码研究
|
6月前
|
安全 Java 测试技术
滚雪球学Java(50):理解Java中String、StringBuilder和StringBuffer的区别与选择
【6月更文挑战第4天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
44 0
滚雪球学Java(50):理解Java中String、StringBuilder和StringBuffer的区别与选择