Java中String、StringBuffer和StringBuilder的区别

Java中String、StringBuffer和StringBuilder的区别

       在Java中String、StringBuffer和StringBuilder是处理字符串常用的类,三者都封装在java.lang包中,三者都被final修饰,所以不能被继承。所以主要从三者的可变性、性能和安全性讨论三者的不同:

三者的结构:

一、可变性

1、String:String为字符串常量,即String对象创建后不能被修改,每次对字符串操作都会产生新的对象,旧的对象会被GC回收。使用字符数组保存字符串:private final char value[ ];

(1)、以赋值方式创建时,会到Java方法空间的字符串常量池中寻找,如果没有则会创建一个并返回内存地址赋值给对象变量,如果有就返回字符串常量池中返回内存地址赋值给对象变量

(2)、以new方式创建时,则直接在堆中开辟空间,返回地址赋值给对象变量,不会去字符串常量池中寻找。

(3)、String对象的修改假象

1 String str = “hello”;
2 str=str + “world”;
3 System.out.println(str);

 

当我们执行上面上面代码是控制台输出:helloworld,String看似被修改了,其实这是个假象。整个执行过程是这样的:

  1. 执行String str = “hello”时,先创建一个str对象,在堆中开辟一个空间存放“hello”,并把内存地址赋值给str;
  2. 执行str = str + “world”时,先在堆内存中开辟新的空间存放“world”,然后再开辟新的内存空间存放str + “world”,即“hello world”,然后将“hello world”在堆中的内存地址返回赋值给str;
  3. System.out.println(str):输出。

 2、StringBuffer与StringBuilder:可改变的Unicode字符序列,两者的对象是变量,对变量进行操作就是直接对该对象进行更改,而不会再次创建和回收的操作。使用字符数组保存字符串:char[ ] value;

(1)、创建时通过new初始化对象,通过对象调用相应方法;

(2)、StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。

二、性能:StringBuilder > StringBuffer > String

1、StringBulder:没有实现线程安全功能,操作时不需要加锁,所以性能较高;

2、StringBuffer:实现了线程安全,在每次操作时都要判断锁,性能较StringBuilder慢;

3、String:每次操作时都会创建一个新的对象,从而经历了创建新对象,销毁旧对象的过程,所以性能最慢。

三、线程安全

1、StringBulder:没有实现线程安全功能,不具备多线程安全,但是在单线程情景下,性能最高;

2、StringBuffer:方法大都通过synchronized关键字修饰,实现了线程安全;

3、String:对象是不可变,通过final关键字修饰为一个常量,所以是线程安全的。

四、StringBuffer的初始化及扩容

1、StringBuffer():初始容量可以容纳16个字符,当该对象存放的字符大于16时,实体的容量会自动扩容,

2、StringBuffer(int size):可以指定该对象初始化容量为size长度的字符个数,当该对象存放的字符序列大于size时,实体的容量会自动扩容;

3、StringBuffer(String s):可以指定该对象的初始容量为该s字符串的长度再加上16个字符,当该对象存放的字符序列大于初始容量时,实体的容量会自动扩容;

StringBuffer对象可以通过length()方法获取实体中存放的字符序列长度,通过capacity()方法来获取当前实体的实际容量。

扩容算法:
1、使用append()方法在字符串后面追加东西的时候,如果长度超过了该字符串存储空间大小了就需要进行扩容:构建新的存储空间来存储更大的字符串,将旧的复制过去;
2、再进行字符串append添加的时候,会先计算添加后字符串大小,传入一个方法:ensureCapacityInternal 这个方法进行是否扩容的判断,需要扩容就调用expandCapacity方法进行扩容;
3、尝试将新容量扩为大小变成2倍+2   if 判断一下 容量如果不够,直接扩充到需要的容量大小。

(五)、StringBuilder与StringBuffer的共同点

1、都有一个公共的AbstractStringBulder抽象类;

2、都会调用AbstractStringBuilder方法,如super.append(...),只是StringBuffer为了实现线程安全,会用关键字synchronized修饰

3、都是final关键字修饰的类,不允许被继承。

(六)、总结

1、String:适用于字符串少量操作的情况;

2、StringBuffer:适用于在多线程环境下字符串大量操作的情况;

3、StringBuilder:适用于在单线程环境下字符串大量操作的情况。

 

以上是我自己平时学习的一个小知识点,如果有错误的地方,欢迎大家批评指正,谢谢!!

posted @ 2020-04-20 17:26  凌倾-学无止境  阅读(259)  评论(0编辑  收藏  举报