string类和stringbuffer类的区别_stringbuffer底层

StringBuffer类(或者StringBuilder)和String一样,也用来代表字符串,只是由于StringBuffer的内部实现方式和String不同,所以StringBuffer在进行字符串处理时,不生成新的对象,在内存使用上要优于String类。

所以在实际使用时,如果经常需要对一个字符串进行修改,例如插入、删除等操作,使用StringBuffer要更加适合一些。

在StringBuffer类中存在很多和String类一样的方法,这些方法在功能上和String类中的功能是完全一样的。

但是有一个最显著的区别在于,对于StringBuffer对象的每次修改都会改变对象自身,这点是和String类最大的区别。

另外由于StringBuffer是线程安全的,关于线程的概念后续有专门的章节进行介绍,所以在多线程程序中也可以很方便的进行使用,但是程序的执行效率相对来说就要稍微慢一些。

1、StringBuffer对象的初始化

StringBuffer对象的初始化不像String类的初始化一样,Java提供的有特殊的语法,而通常情况下一般使用构造方法进行初始化。

例如:

StringBuffer s = new StringBuffer();

1

这样初始化出的StringBuffer对象是一个空的对象。

如果需要创建带有内容的StringBuffer对象,则可以使用:

StringBuffer s = new StringBuffer(“abc”);

这样初始化出的StringBuffer对象的内容就是字符串”abc”。

需要注意的是,StringBuffer和String属于不同的类型,也不能直接进行强制类型转换,下面的代码都是错误的:

StringBuffer s = “abc”; //赋值类型不匹配

tringBuffer s = (StringBuffer)”abc”; //不存在继承关系,无法进行强转

StringBuffer对象和String对象之间的互转的代码如下:

String s = “abc”;

StringBuffer sb1 = new StringBuffer(“123”);

StringBuffer sb2 = new StringBuffer(s); //String转换为StringBuffer

String s1 = sb1.toString(); //StringBuffer转换为String

2、StringBuffer的常用方法

StringBuffer类中的方法主要偏重于对于字符串的变化,例如追加、插入和删除等,这个也是StringBuffer和String类的主要区别。

a、append方法

public StringBuffer append(boolean b)

该方法的作用是追加内容到当前StringBuffer对象的末尾,类似于字符串的连接。调用该方法以后,StringBuffer对象的内容也发生改变,例如:

StringBuffer sb = new StringBuffer(“abc”);

sb.append(true);

则对象sb的值将变成”abctrue”。

使用该方法进行字符串的连接,将比String更加节约内容,例如应用于数据库SQL语句的连接,例如:

StringBuffer sb = new StringBuffer();

String user = “test”;

String pwd = “123”;

sb.append(“select * from userInfo where username=“)

.append(user)

.append(“ and pwd=”)

.append(pwd);

这样对象sb的值就是字符串“select * from userInfo where username=test and pwd=123”。

b、deleteCharAt方法

public StringBuffer deleteCharAt(int index)

该方法的作用是删除指定位置的字符,然后将剩余的内容形成新的字符串。例如:

StringBuffer sb = new StringBuffer(“Test”);

sb. deleteCharAt(1);

该代码的作用删除字符串对象sb中索引值为1的字符,也就是删除第二个字符,剩余的内容组成一个新的字符串。所以对象sb的值变为”Tst”。

还存在一个功能类似的delete方法:

public StringBuffer delete(int start,int end)

该方法的作用是删除指定区间以内的所有字符,包含start,不包含end索引值的区间。例如:

StringBuffer sb = new StringBuffer(“TestString”);

sb. delete (1,4);

该代码的作用是删除索引值1(包括)到索引值4(不包括)之间的所有字符,剩余的字符形成新的字符串。则对象sb的值是”TString”。

c、insert方法

public StringBuffer insert(int offset, boolean b)

该方法的作用是在StringBuffer对象中插入内容,然后形成新的字符串。例如:

StringBuffer sb = new StringBuffer(“TestString”);

sb.insert(4,false);

该示例代码的作用是在对象sb的索引值4的位置插入false值,形成新的字符串,则执行以后对象sb的值是”TestfalseString”。

d、reverse方法

public StringBuffer reverse()

该方法的作用是将StringBuffer对象中的内容反转,然后形成新的字符串。例如:

StringBuffer sb = new StringBuffer(“abc”);

sb.reverse();

转以后,对象sb中的内容将变为”cba”。

e、setCharAt方法

public void setCharAt(int index, char ch)

该方法的作用是修改对象中索引值为index位置的字符为新的字符ch。例如:

StringBuffer sb = new StringBuffer(“abc”);

sb.setCharAt(1,’D’);

则对象sb的值将变成”aDc”。

f、trimToSize方法

public void trimToSize()

该方法的作用是将StringBuffer对象的中存储空间缩小到和字符串长度一样的长度,减少空间的浪费。

总之,在实际使用时,String和StringBuffer各有优势和不足,可以根据具体的使用环境,选择对应的类型进行使用。

String和StringBuffer的效率对比

为了更加明显地看出它们的执行效率,下面的代码,将26个英文字母加了10000次。

public class Demo {

public static void main(String args){

String fragment = “abcdefghijklmnopqrstuvwxyz”;

int times = 10000;

// 通过String对象

long timeStart1 = System.currentTimeMillis();

String str1 = “”;

for (int i=0; i<times; i++) {

str1 += fragment;

}

long timeEnd1 = System.currentTimeMillis();

System.out.println(“String: ” + (timeEnd1 – timeStart1) + “ms”);

// 通过StringBuffer

long timeStart2 = System.currentTimeMillis();

StringBuffer str2 = new StringBuffer();

for (int i=0; i<times; i++) {

str2.append(fragment);

}

long timeEnd2 = System.currentTimeMillis();

System.out.println(“StringBuffer: ” + (timeEnd2 – timeStart2) + “ms”);

}

}

运行结果:

String: 5287ms

StringBuffer: 3ms

结论很明显,StringBuffer的执行效率比String快上千倍,这个差异随着叠加次数的增加越来越明显,当叠加次数达到30000次的时候,运行结果为:

String: 35923ms

StringBuffer: 8ms

所以,强烈建议在涉及大量字符串操作时使用StringBuffer。

StringBuilder类

StringBuilder类和StringBuffer类功能基本相似,方法也差不多,主要区别在于StringBuffer类的方法是多线程安全的,而StringBuilder不是线程安全的,相比而言,StringBuilder类会略微快一点。

StringBuffer、StringBuilder、String中都实现了CharSequence接口。

CharSequence是一个定义字符串操作的接口,它只包括length()、charAt(int index)、subSequence(int start, int end) 这几个API。

StringBuffer、StringBuilder、String对CharSequence接口的实现过程不一样,如下图所示:

string类和stringbuffer类的区别_stringbuffer底层

可见,String直接实现了CharSequence接口;StringBuilder 和 StringBuffer都是可变的字符序列,它们都继承于AbstractStringBuilder,实现了CharSequence接口。

jdk的实现中StringBuffer与StringBuilder都继承自AbstractStringBuilder,对于多线程的安全与非安全看到StringBuffer中方法前面的一堆synchronized就大概了解了。

string类和stringbuffer类的区别_stringbuffer底层

string类和stringbuffer类的区别_stringbuffer底层

我们知道使用StringBuffer等无非就是为了提高java中字符串连接的效率,因为直接使用+进行字符串连接的话,jvm会创建多个String对象,因此造成一定的开销。

AbstractStringBuilder中采用一个char数组来保存需要append的字符串,char数组有一个初始大小,当append的字符串长度超过当前char数组容量时,则对char数组进行动态扩展,也即重新申请一段更大的内存空间,然后将当前char数组拷贝到新的位置,因为重新分配内存并拷贝的开销比较大,所以每次重新申请内存空间都是采用申请大于当前需要的内存空间的方式,这里是2倍。

分类总结如下:

(1)StringBuffer在进行追加操作的时候,只是在字符串的后边进行追加操作,追加的过程也是需要进行判断预存数组大小是否超过一开始设定的16子字符,然后才可以进行追加,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。;由于StringBuilder和StringBuffer本身都是继承自AbstractStringBuilder,在进行追加操作的时候,使用的就是AbstractStringBuilder类中的append方法,下图中展示了AbstractStringBuilder类中所有重载的append方法,根据不同的需求可以实现不同的功能,

string类和stringbuffer类的区别_stringbuffer底层

以append(CharSequence s)为例,展示一下:(下边的方法都是AbstractStringBuilder中的方法)

@Override

public AbstractStringBuilder append(CharSequence s) {

if (s == null)

return appendNull();

if (s instanceof String)

return this.append((String)s);

if (s instanceof AbstractStringBuilder)

return this.append((AbstractStringBuilder)s);

return this.append(s, 0, s.length());

}

首先进行判断是否为空,然后判断是哪一个实例,最后掉用append另一个重载的方法:

@Override

public AbstractStringBuilder append(CharSequence s, int start, int end) {

if (s == null)

s = “null”;

if ((start < 0) || (start > end) || (end > s.length()))

throw new IndexOutOfBoundsException(

“start ” + start + “, end ” + end + “, s.length() “

+ s.length());

int len = end – start;

ensureCapacityInternal(count + len);

for (int i = start, j = count; i < end; i++, j++)

value = s.charAt(i);

count += len;

return this;

}

其中:

/**

* The count is the number of characters used.

*/

int count;

/**

* The value is used for character storage.

*/

char value;

可以看出:ensureCapacityInternal(count + len); 是一个扩容的过程,value = s.charAt(i); 是保存追加字符串的过程,具体的过程就是再原StringBuffer对象的基础上首先通过扩容,之后在进行追加操作;

(2)StringBuffer的四个构造方法如下:

StringBuffer()

构造一个其中不带字符的字符串缓冲区,其初始容量为 16 个字符。

StringBuffer(CharSequence seq)

public java.lang.StringBuilder(CharSequence seq) 构造一个字符串缓冲区,它包含与指定的 CharSequence 相同的字符。

StringBuffer(int capacity)

构造一个不带字符,但具有指定初始容量的字符串缓冲区。

StringBuffer(String str)

构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容

每个字符串缓冲区都有一定的容量。只要字符串缓冲区所包含的字符序列的长度没有超出此容量,就无需分配新的内部缓冲区数组。如果内部缓冲区溢出,则此容量自动增大。从 JDK 5 开始,为该类补充了一个单个线程使用的等价类,即 StringBuilder。与该类相比,通常应该优先使用 StringBuilder 类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快。

(3)而对于String来说,虽然追加(字符串串联)的本质也是通过创建StringBuilder对象,通过StringBuilder的append方法来实现的,但是每次追加的过程都是一次创建StringBuilder对象的过程,因也就是说在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,效率显然要比直接使用StringBuilder来说要低很多,网上也有很多测试的实验,也充分说明这一点,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的;

(4)而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:

String S1 = “This is only a” + “ simple” + “ test”;

StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);

会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在JVM 眼里,这个String S1 = “This is only a” + “ simple” + “test”;

其实就是: String S1 = “This is only a simple test”;

所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如:

String S2 = “This is only a”;

String S3 = “ simple”;

String S4 = “ test”;

String S1 = S2 +S3 + S4;

这时候 JVM 会规规矩矩的按照原来的方式去做, S1 对象的生成速度就不像刚才那么快了,一会儿我们可以来个测试作个验证。

由此我们得到第一步结论: 在大部分情况下 StringBuffer > String

(4)总的来说,StringBuilder适合于需要进行经常性的字符追加删除操作等,String本身设计的初衷应该是为了在后边的使用过程种,不会进行太多的增删操作,毕竟String是final类型的,是不可变的对象,因此他们都有所擅长的地方,根据自己的需求进行合理的选择即可;

总结

线程安全:

StringBuffer:线程安全

StringBuilder:线程不安全

速度:

一般情况下,速度从快到慢为 StringBuilder > StringBuffer > String,当然这是相对的,不是绝对的。

使用环境:

操作少量的数据使用 String;

单线程操作大量数据使用 StringBuilder;

多线程操作大量数据使用 StringBuffer。

本文【string类和stringbuffer类的区别_stringbuffer底层】由作者: 外键 提供,本站不拥有所有权,只提供储存服务,如有侵权,联系删除!
本文链接:https://www.cuoshuo.com/blog/4149.html

(0)
上一篇 2023-03-09 08:46:44
下一篇 2023-03-09 08:54:02

相关推荐

  • 遗传算法原理及应用pdf_遗传算法与工程优化pdf

    遗传算法 ( GA , GeneticAlgorithm ) ,也称进化算法 。 遗传算法是受达尔文的进化论的启发,借鉴生物进化过程而提出的一种启发式搜索算法。因此在介绍遗传算法前有必要简单地介绍生物进化知识。 一.进化论知识 作为遗传算法生物背景的介绍,下面内容了解即可: 种群(Population):生物的进化以群体的形式进行,这样的一个群体称为种群。 …

    2023-03-18
    000
  • c语言贪吃蛇程序设计流程图_文本文档简单贪吃蛇代码

    C语言是一种计算机程序设计语言,它既有高级语言的特点,又具有低级汇编语言的特点。它可以作为系统设计语言来编写工作系统应用程序,也可以作为应用程序设计语言来编写不依赖计算机硬件的应用程序。因此,它的应用范围非常广泛。 C语言的诞生及发展历程如图所示。 第1阶段:A语言 C语言的发展颇为有趣,它的原型是ALGOL 60语言,也称A语言。ALGOL 60是一种面向…

    2023-03-08
    500
  • jquery特效的设计与制作

    最近在学习jquery,发现jquery上手比javascript容易许多,因为有着良好的文档和帮助手册,如果遇到一些问题可以借助文档来解决。初步接触学习jquery,我发现学习jquery主要是学会如何使用内置的方法。 今天就跟大家一起分享下,我用jquery写的一个banner全屏特效切换的案例,以及制作它运用了哪些jquery内置方法。 思路: 注:这…

    2023-03-16
    300
  • 全栈工程师需要掌握哪些知识_全栈工程师需要学多久

    Web前端工程师可能大家知道是干嘛的,你知道Web全栈工程师是什么吗?Web全栈工程师也是前端开发工程师的一种,而且通过前端培训也是能成为Web全栈工程师的。那么,学web前端开发需要多久?Web全栈工程师需要掌握哪些技术呢? Web全栈工程师是什么? Web全栈开发工程师,主要职责是利用 HTML/CSS/Java/DOM/Flash等各种Web技术进行产…

    2023-03-18
    200
  • bmp格式如何转换成jpg_bmp文件怎么转换成jpg

    bmp怎么改jpg格式?jpg是一种用最小的体积来展现了最好图片质量的格式,直白一点说就是jpg体积小,同时又拥有不错的图片质量,另外jpg兼容性也高,支持打开的编辑工具特别多,所以是图片的首选的保存格式。而且在遇到另外一些不好使用的图片格式时,也都会选择将其转换成jpg来使用。比如遇到bmp格式,这种格式所包含的图像信息非常丰富,几乎是无损压缩的。这由此导…

    2023-03-21
    000
  • 自然语言处理包括哪些内容_自然语言处理的应用

    对于ChatGPT来说,相信各位最近都被它铺天盖地的新闻报道所淹没,肯定还有不少人已经体验到了ChatGPT,大有人工智能已经高度进化之势。ChatGPT的出现,好像已经对当今互联网产生了巨大的影响,如果在这么发展下去,甚至看到了在未来能代替不少职业的趋势,比如客服、编程、广告、秘书工作等等。 什么是ChatGPT呢?ChatGPT,是美国OpenAI研发的…

    2023-03-12
    500
  • 电脑运行关闭启动项命令

    方法一: 1.使用命令键(Win + R)打开运行窗口,输入:msconfig,然后单击“确定”。 2.您还可以在附件下方左下角的开始菜单中查看操作。 3.选择“启动”,删除不想在启动时启动的应用程序,然后在删除后单击“确定”。 4.单击重新启动以生效,或单击以在空闲时退出并重新启动。 方法二: 1.您可以在“任务管理器”中直接关闭不必要的启动项。 2.右键…

    2023-03-15
    200
  • 繁体中文语言包含哪些

    主编:王炫 2020.3.4. 古逸書院:古須合乎“高古,古質,古樸”之詞義,能尋原始自然之蒼茫,可養樸拙雄渾之氣格;“逸”出古賢畫評之格“逸品”,“逸品”遂於意象之間,超乎筆墨之外,意簡神清,秀骨藏於內,古心以入幽,變幻莫測,雅然天成。今立古逸書院,宗旨於培養學子具獨立之思維,獨立之人格,汲古進以得超凡創造之藝才。 何为繁体字? 2.何为异体字? 异体字,…

    2023-03-16
    100
  • 电脑编程学了可以干什么_学电脑编程能干什么

    很多人都知道IT行业好,IT行业收入高,知道自己需要学习,但是具体又不知道学习完毕后,自己学习的内容可以从事哪些工作内容。今天小卓就为你梳理一下学习完编程后,可以从事哪些行业,发展如何? 01互联网 最直接的工作就是到一个科技企业做程序员,人家码砖头,我们码代码。目前的互联网行业,那是需要大批的编程人员,把现实中的数据进行转换存储分析。BAT是目前国内比较好…

    2023-03-10
    900
  • 二分法查找是什么意思

    引入: 二分法思想无处不在,我们经常玩的猜数字游戏,0-99的范围,最多需要多少次我就可以猜对呢? 使用二分法思想,最多仅仅需要7次就可以查找到。 二分法查找是非常恐怖的,以2的倍数缩小范围。所以时间复杂度O(logn) 局限性: 1.针对二分法查找的数据必须是有序的。 2.二分法查找依赖于顺序表结构,也就是数组。因为二分法需要随机访问元素,也就是O(1)的…

    2023-03-12
    400

发表回复

登录后才能评论
返回顶部
错说博客上线啦!