String、StringBuilder、StringBuffer的区别

它们之间的区别:

在我们学习String类的时候,也会学习到StringBuilder和StringBuffer,但是他们之间有什么区别呢? 当然他们在具体的代码实现上、内存分配上以及效率上都有着不同(我这里以JDK8为例);

一、代码实现
String

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {/** The value is used for character storage. */private final char value[];/** Cache the hash code for the string */private int hash; // Default to 0/** use serialVersionUID from JDK 1.0.2 for interoperability */private static final long serialVersionUID = -6849794470754667710L;/*** Class String is special cased within the Serialization Stream Protocol.** A String instance is written into an ObjectOutputStream according to* <a href="{@docRoot}/../platform/serialization/spec/output.html">* Object Serialization Specification, Section 6.2, "Stream Elements"</a>*/private static final ObjectStreamField[] serialPersistentFields =new ObjectStreamField[0];/*** Initializes a newly created {@code String} object so that it represents* an empty character sequence.  Note that use of this constructor is* unnecessary since Strings are immutable.*/public String() {this.value = "".value;}/*** Initializes a newly created {@code String} object so that it represents* the same sequence of characters as the argument; in other words, the* newly created string is a copy of the argument string. Unless an* explicit copy of {@code original} is needed, use of this constructor is* unnecessary since Strings are immutable.** @param  original*         A {@code String}*/public String(String original) {this.value = original.value;this.hash = original.hash;}

从这里我们可以看出,String的底层结构是private final char value[];所以String的值是不可变的,并且实现了Comparable接口,所以是支持比较的。

StringBuilder

public final class StringBuilderextends AbstractStringBuilderimplements java.io.Serializable, CharSequence
{/** use serialVersionUID for interoperability */static final long serialVersionUID = 4383685877147921099L;/*** Constructs a string builder with no characters in it and an* initial capacity of 16 characters.*/public StringBuilder() {super(16);}/*** Constructs a string builder with no characters in it and an* initial capacity specified by the {@code capacity} argument.** @param      capacity  the initial capacity.* @throws     NegativeArraySizeException  if the {@code capacity}*               argument is less than {@code 0}.*/public StringBuilder(int capacity) {super(capacity);}/*** Constructs a string builder initialized to the contents of the* specified string. The initial capacity of the string builder is* {@code 16} plus the length of the string argument.** @param   str   the initial contents of the buffer.*/public StringBuilder(String str) {super(str.length() + 16);append(str);}/*** Constructs a string builder that contains the same characters* as the specified {@code CharSequence}. The initial capacity of* the string builder is {@code 16} plus the length of the* {@code CharSequence} argument.** @param      seq   the sequence to copy.*/public StringBuilder(CharSequence seq) {this(seq.length() + 16);append(seq);}@Overridepublic StringBuilder append(Object obj) {return append(String.valueOf(obj));}@Overridepublic StringBuilder append(String str) {super.append(str);return this;}

从这里我们可以看出StringBuilder有一个抽象父类,他是没有实现Comparable接口,明显不支持比较。我们看到AbstractStringBuilder类中,value是可变的,并不像String有final修饰

AbstractStringBuilder

abstract class AbstractStringBuilder implements Appendable, CharSequence {/*** The value is used for character storage.*/char[] value;/*** The count is the number of characters used.*/int count;/*** This no-arg constructor is necessary for serialization of subclasses.*/AbstractStringBuilder() {}

StringBuffer

public final class StringBufferextends AbstractStringBuilderimplements java.io.Serializable, CharSequence
{/*** A cache of the last value returned by toString. Cleared* whenever the StringBuffer is modified.*/private transient char[] toStringCache;/** use serialVersionUID from JDK 1.0.2 for interoperability */static final long serialVersionUID = 3388685877147921107L;/*** Constructs a string buffer with no characters in it and an* initial capacity of 16 characters.*/public StringBuffer() {super(16);}/*** Constructs a string buffer with no characters in it and* the specified initial capacity.** @param      capacity  the initial capacity.* @exception  NegativeArraySizeException  if the {@code capacity}*               argument is less than {@code 0}.*/public StringBuffer(int capacity) {super(capacity);}/*** Constructs a string buffer initialized to the contents of the* specified string. The initial capacity of the string buffer is* {@code 16} plus the length of the string argument.** @param   str   the initial contents of the buffer.*/public StringBuffer(String str) {super(str.length() + 16);append(str);}/*** Constructs a string buffer that contains the same characters* as the specified {@code CharSequence}. The initial capacity of* the string buffer is {@code 16} plus the length of the* {@code CharSequence} argument.* <p>* If the length of the specified {@code CharSequence} is* less than or equal to zero, then an empty buffer of capacity* {@code 16} is returned.** @param      seq   the sequence to copy.* @since 1.5*/public StringBuffer(CharSequence seq) {this(seq.length() + 16);append(seq);}@Overridepublic synchronized int length() {return count;}@Overridepublic synchronized int capacity() {return value.length;}

而StringBuffer同样是继承一个抽象父类AbstractStringBuilder,它的底层结构同样是可变的char[] value数组也没有实现Comparable接口。

StringBuffer和StringBuilder虽然结构是一样的,但还是有不同点。StringBuffer多了几样东西。
如:
1、toStringCache它是用于执行toString()方法时,把值保存到变量中,下次继续执行toString()方法时,可以直接从变量中取出来。变量是transient 修饰的,代表着不可序列化。
2、还有一个本质上的区别,StringBuffer的方法是synchronized修饰的,代表着是线程安全的。

二、性能效率
String

//        StirngString str = "";long oldTime = System.currentTimeMillis();for (int i = 0; i < 100000; i++) {str += "a";}System.out.printf("耗时:%d ms",(System.currentTimeMillis() - oldTime));

我这里使用for循环,每循环一次,都往str中拼接字符串"a",总共循环10万次。执行时间达到了平均11秒,太可怕了,效率实在太慢太慢了。

StringBuilder

//      StringBuilderStringBuilder str = new StringBuilder("");long oldTime = System.currentTimeMillis();for (int i = 0; i < 10000000; i++) {str.append("a");}System.out.printf("耗时:%d ms",(System.currentTimeMillis() - oldTime));

我这里使用StringBuilder的append方法进行拼接字符串,拼接1000万次,平均执行时间只需279毫秒,这里对比String可以看出,在大量拼接字符串的时候,String的劣势很明显。
当然StringBuilder虽然够快,但也有他的劣势,在多线程的环境下是线程不安全的。

StringBuffer

//        StringBufferStringBuffer str = new StringBuffer("");long oldTime = System.currentTimeMillis();for (int i = 0; i < 10000000; i++) {str.append("a");}System.out.printf("耗时:%d ms",(System.currentTimeMillis() - oldTime));

这里同样使用StringBuffer拼接字符串,同样1000万次,耗时平均550毫秒。虽然它没有StringBuilder快,但是它可以保证线程安全,我们前面讲过StringBuffer的方法是synchronized修饰的。当然线程安全就代表着它性能效率会被降低了,因为我们的线程需要去竞争锁,竞争到锁的线程才可以执行,虽然有偏向锁,性能难免会被降低。

三、内存分配

JVM内存区域划分如下(自画,如果有觉得错的地方,可以私信我修正哈)

在这里插入图片描述

String

String str = “a” + “b” + “c”; //我们以这段代码为例,我们来看看内存中是如何分配的

在这里插入图片描述
【总所周知,字符串常量池在JDK7中从方法区搬到了堆中!】
(字面量:字符串常量池中带"“双引号的字,如"a”、“b”、"c"都是字面量)
我们可以看到,在使用String进行拼接不同字符串的时候,每次拼接相连,都会在常量池中创建相应的字面量。这是因为String的value是final修饰的,并不能直接修改,所以会一直创建新的对象,并重新进行赋值。

在JDK9中,String底层是“byte[]”,并不是“char[]”了,这样做的目的就是可以通过编码的方式来存储,可以减少内存的占用和提高性能,我测试过性能快了不止一倍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/557568.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2016年 java_2016年java考试试题及答案

2016年java考试试题及答案简答应用题1.下面程序运行后&#xff0c;可以使用上下左右键移动组件。 补充下画线部分的代码。import java.awt.*;import java.awt.event.*;public class E6 extends Frame implements keyListener{TextField b1;int x,y;E6(){setLayout (new FlowLay…

【Java深入理解】String str = “a“ + “b“ + “c“到底创建了几个对象?

String str “a” “b” “c"到底创建了几个对象&#xff1f;这是我们在讨论中最经常遇到的一个问题同时也是面试题。我们都知道在Java中从”.java"文件编译成".class"文件的过程&#xff0c;会有一个优化器去优化我们的代码。这个问题需要分成三种情况…

java quartz tomcat_Quartz Scheduler - 在Tomcat或应用程序jar中运行?

我们有一个Web应用程序&#xff0c;它通过在Jersey / Tomcat / Apache / PostgreSQL上运行的RESTful Web服务接收传入数据 . 与此Web服务应用程序分开&#xff0c;我们需要执行许多重复和计划任务 . 例如&#xff0c;以不同的时间间隔清除不同类型的数据&#xff0c;在不同的时…

php post json请求参数传递_php post json参数的传递和接收处理方法

页面1 &#xff0c;php传递json参数的页面&#xff1a;1.phpfunction http_post_data($url, $data_string) {$ch curl_init();curl_setopt($ch, CURLOPT_POST, 1);curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);curl_setopt($ch, …

Linux中如何查看某个端口是否被占用

Linux中如何查看某个端口是否被占用 1.netstat -anp |grep 端口号 如下&#xff0c;我以3306为例&#xff0c;netstat -anp |grep 3306&#xff08;此处备注下&#xff0c;我是以普通用户操作&#xff0c;故加上了sudo&#xff0c;如果是以root用户操作&#xff0c;不用加sudo…

java 压缩jar 仓库,java服务安装(一):使用java service wrapper及maven打zip包

tags&#xff1a; java jsw maven zip1、概述使用java开发程序&#xff0c;在windows平台下&#xff0c;一般有web应用&#xff0c;后台服务应用&#xff0c;桌面应用&#xff1a;web应用多数打成war包在web容器(如tomcat,jetty等)中运行桌面应用一般打成jar包或exe文件运行后台…

如何处理代码冲突

如何处理代码冲突 冲突合并一般是因为自己的本地做的提交和服务器上的提交有差异&#xff0c;并且这些差异中的文件改动&#xff0c;Git不能自动合并&#xff0c;那么就需要用户手动进行合并 如我这边执行git pull origin master 如果Git能够自动合并&#xff0c;那么过程看…

php试题与答案(二),php面试题附答案二

1、如何实现字符串翻转&#xff1f;function getStr($str){$lenstrlen($str);for ($i0;$i$temp$str[$i];$str[$i]$str[$len-$i-1];$str[$len-$i-1]$temp;}return $str;}echo getStr("abcdef");?>2、apachemysqlphp实现最大负载的方法&#xff1f;个人观点&#x…

如何理解NIO

文章目录1.什么是NIO&#xff1f;2.为什么用NIO&#xff0c;传统IO有什么缺陷&#xff1f;3.NIO和IO的区别4.怎么理解NIO是面向块的、非阻塞的5.NIO是怎么实现的&#xff1f;1.什么是NIO&#xff1f; java.nio全称java non-blocking IO&#xff08;实际上是 new io&#xff09…

sublime php快捷键,分享Sublime Text 3快捷键精华版!

下面由sublime教程栏目给大家介绍Sublime Text 3 快捷键精华版&#xff0c;希望对需要的朋友有所帮助&#xff01;CtrlShiftP&#xff1a;打开命令面板CtrlP&#xff1a;搜索项目中的文件CtrlG&#xff1a;跳转到第几行CtrlW&#xff1a;关闭当前打开文件CtrlShiftW&#xff1a…

MyBatis Plus——忽略某个实体类属性和数据库表字段之间的映射关系

问题描述 在开发中可能会遇到MyBatis-Plus使用实体类属性进行SQL操作&#xff0c;但是不用存到数据库中去查找&#xff0c;这时候我们的实体中有这个属性&#xff0c;但是数据库的表中没有这个字段(即&#xff1a;实体类属性非数据库表字段)&#xff0c;如果不做处理就会报错。…

php 高德地图计算距离,距离、长度、面积

JS API 为开发者提供了空间数据计算的函数库 AMap.GeometryUtil&#xff0c;可以帮助开发者计算点线面空间关系、长度、面积等函数。更多示例请查看 示例中心本章我们将介绍一些常用的数学计算方法&#xff0c;包括&#xff1a;计算两点间的实际距离 AMap.GeometryUtil.distanc…

@Transient注解作用

java 的transient关键字的作用是需要实现Serilizable接口&#xff0c;将不需要序列化的属性前添加关键字transient&#xff0c;序列化对象的时候&#xff0c;这个属性就不会序列化到指定的目的地中。 用法 transient 就是在给某个javabean上需要添加个属性&#xff0c;但是这…

Java隐含对象实验报告,JSP隐含对象response实现文件下载

一.简单介绍JSP隐含对象response实现文件下载(1)在JSP中实现文件下载最简单的方法是定义超链接指向目标资源&#xff0c;用户单击超链接后直接下载资源&#xff0c;但直接暴露资源的URL也会带来一些负面的影响&#xff0c;例如容易被其它网站盗链&#xff0c;造成本地服务器下载…

JDBC中使用preparedStatement防止SQL注入

一、SQL注入 SQL注入是一种比较常见的网路攻击方式&#xff0c;一些恶意人员在需要用户输入的地方&#xff0c;恶意输入SQL语句的片段&#xff0c;通过SQL语句&#xff0c;实现无账号登录&#xff0c;甚至篡改数据库。 二、SQL注入实例 登录场景&#xff1a; 在一个登录界面…

Java预科篇1-学前

Java预科篇1-学前 1、markdown语法 Markdown是一种纯文本格式的标记语言。通过简单的标记语法&#xff0c;它可以使普通文本内容具有一定的格式。 优点&#xff1a; 因为是纯文本&#xff0c;所以只要支持Markdown的地方都能获得一样的编辑效果&#xff0c;可以让作者摆脱排…

Java预科篇2-环境搭建

Java预科篇2-环境搭建 1、Java历史 1995年 Java问世1996年 Java 1.01999年 Java 1.2发布&#xff08;JAVA SE\JAVA EE\JAVA ME&#xff09;… … …2004年 Tiger 发布(JAVA5.0)&#xff0c;Java 登录火星2011年 7月由Oracle正式发布Java7.02014年 3月19日&#xff0c;Oracle公…

php中如何配置环境变量,如何配置phpstorm环境变量如何配置phpstorm环境变量

大话西游6664版。根据你的系统平台下载相应的版本后&#xff0c;如果是压缩文件&#xff0c;先解压后双击运行&#xff0c;不是压缩文件&#xff0c;直接双击运行就可以了&#xff0c;运行后出现下面的界面&#xff0c;在下面界面上单击“Next”。跟所有的软件安装包一样&#…

Java基础篇1——变量与数据类型

Java基础篇1——变量与数据类型 1、标识符命名规则 标识符以由大小写字母、数字、下划线(_)和美元符号($)组成&#xff0c;但是不能以数字开头。大小写敏感不能与Java语言的关键字重名不能和Java类库的类名重名不能有空格、、#、、-、/ 等符号长度无限制应该使用有意义的名称…

php伪静态后301,动态地址rewrite伪静态,然后301跳转到伪静态时死

本文章来给各位同学介绍动态地址rewrite伪静态&#xff0c;然后301跳转到伪静态时死循环解决办法&#xff0c;有碰到此类的朋友可进入参考。问题背景&#xff1a;矿秘书网的历史遗留问题&#xff0c;刚开始由于各种问题&#xff0c;一些动态页面都是用了?id参数的形式&#xf…