解析Java中String、StringBuilder以及StringBuffer

深入解析Java字符串三剑客:String、StringBuffer、StringBuilder 特性String可变性❌✅✅线程安全✅(天然)✅(同步锁)❌性能最低中等最高初始化方式字面量/newnew + 初始容量new + 初始容量内存占用易产生碎片预分配机制预分配机制核心区别记忆三要素可变性 → String不可变线程安全 → 仅StringBuffer安全性能比较 → StringBuilder > StringBuffer > String面试超纲加分点自动装箱对字符串拼接的影响Java 9之后的紧凑字符串优化字符编码对字节数组存储的影响。 阅读详情

一,String类

1,String类的特点(由源码分析)

 

public final class String

    implements java.io.Serializable, Comparable<String>, CharSequence

{

    /** The value is used for character storage. */

    private final char value[];

 

    /** The offset is the first index of the storage that is used. */

    private final int offset;

 

    /** The count is the number of characters in the String. */

    private final int count;

 

    /** 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; 

}

由上可知:

(1)String类被final修饰,所以String类不能被继承,也是线程安全的

(2) private final char value[];//用于存储字符串

private int hash; // 缓存String的hash值

(3)String类的方法实现:(源码)

 

  public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }

 从上面方法可以看出,concat操作不是在原有的字符串上进行的,而是重新生成了一个新的字符串对象。也就是说进行这些操作后,最原始的字符串并没有被改变。

注释:1String的方法split可以有两个参数,及第二个参数可以规定,生成数组的长度。

2,String的创建存储以及比较

  字符串的两种创建方式:String str="fuheiuG";(存储在常量池中) String str=new string("fgaueiug");(new对象存储在堆中)

JVM内存机制中,在class文件中有一部分 来存储编译期间生成的 字面常量以及符号引用,这部分叫做class文件常量池,在运行期间对应着方法区的运行时常量池。

  因此在上述代码中,String str1 = "hello world";和String str3 = "hello world"; 都在编译期间生成了 字面常量和符号引用,运行期间字面常量"hello world"被存储在运行时常量池(当然只保存了一份)。通过这种方式来将String对象跟引用绑定的话,JVM执行引擎会先在运行时常量池查找是否存在相同的字面常量,如果存在,则直接将引用指向已经存在的字面常量;否则在运行时常量池开辟一个空间来存储该字面常量,并将引用指向该字面常量。

  总所周知,通过new关键字来生成对象是在堆区进行的,而在堆区进行对象生成的过程是不会去检测该对象是否已经存在的。因此通过new来创建对象,创建出的一定是不同的对象,即使字符串的内容是相同的。

例如:public class StringCompare {
  public static void A() {
    String str1 = "java";
    String str2 = "java";
    System.out.println(str1 == str2);  //true  原因很简单,String对象被放进常量池里了,再次出现“java”字符串的时候,JVM很兴奋地把str2的引用也指向了 “java”对象,它认为自己节省了内存开销
  }
  public static void B() {
    String str1 = new String("java");
    String str2 = new String("java");
    System.out.println(str1 == str2);  //false  new是在堆中创建了两个不同的对象。
  }

 public static void D() {
    String s1 = "java";
    String s2 = new String("java");
    System.out.println(s1 == s2.);  //false,  ==比较引用,因为对象在不同的位置创建。所以对象不可能相同。
  }
 public static void D2() {
    String s1 = "java";
    String s2 = new String("java");
    System.out.println(s1 == s2.intern());  //true,  使用intern方法可以通过==比较对象的内容,实质上intern方法运行时会在常量池中查找是否存在内容相同的字符串,如果存在则返回指向该字符串的引用,如果不存在,则会将该字符串入池,并返回一个指向该字符串的引用。       intern()方法主要可以用来避免创建内容重复的String对象,值得我们重视。

  public static void C() {
    String str1 = "java";
    String str2 = "blog";
    String s = str1 + str2;
    System.out.println(s == "javablog");  //false   str1和str2和Javablog在编译时刻就已经放在常量池中了,二s是在运行期间在堆中创建,所以s引用不可能指向常量池中的对象。
  }
  public static void C2() {
    String str1 = "javablog";
    String str2 = "java"+"blog";    //在编译时被优化成String str2 = "javablog";
    System.out.println(str1 == str2);  //true
  }
  public static void E() {
    String str1 = "java";
    String str2 = new String("java");
    System.out.println(str1.equals(str2));  //true     无论在常量池还是堆中的对象,用equals()方法比较的就是内容,就这么简单!
  }

 StringBuffer的insert方法:

1

2

3

4

5

6

public synchronized StringBuffer insert(int index, char str[], int offset,

                                            int len)

    {

        super.insert(index, str, offset, len);

        return this;

    }

二, String vs StringBuilder vs StringBuffer

1,三者之间的区别:
StringBuilder 是可变的,因此可以在创建以后修改内部的值.(适用于单线程下在字符缓冲区进行大量操作的情况)
StringBuffer 是同步的,因此是线程安全的,但效率相对更低.(适用多线程下在字符缓冲区进行大量操作的情况)

String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,对变量进行操作就是直接对该对象进行更改,而不进行           创建和回收的操作,所以速度要比String快很多。

在运行速度方面:StringBuilder > StringBuffer > String,所以在不考虑线程安全的情况下(即单线程的情况下)应使用StringBuilder。。多线程的情况下应使用StringBuffer。

例如:

4

5

6

7

8

9

public class Main {

         

    public static void main(String[] args) {

        String string = "";

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

            string += "hello";

        }

    }

}

  这句 string += "hello";的过程相当于将原有的string变量指向的对象内容取出与"hello"作字符串相加操作再存进另一个新的String对象当中,再让string变量指向新生成的对象。

      string+="hello"的操作事实上会自动被JVM优化成StringBuilder进行操作。

1

2

3

4

5

6

7

8

9

public class Main {

         

    public static void main(String[] args) {

        StringBuilder stringBuilder = new StringBuilder();

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

            stringBuilder.append("hello");

        }

    }

        这里new操作只进行了一次,也就是说只生成了一个对象,append操作是在原有对象的基础上进行的。因此这段代码所占的资源要比上面小得多。

2,字符串拼的实质:

  StringBuilder的append() 工作原理,    StringBuilder是调用了其父类的append方法的,我们来看源码:

public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
  public AbstractStringBuilder append(String str) {
        if (str == null) {
            str = "null";
        }
        int len = str.length();
        if (len == 0) {
            return this;
        }

        int newCount = count + len;//统计拼接后字符串长度
        if (newCount > value.length) {
            expandCapacity(newCount);//如果拼接结果大于所用的char[],则扩容
        }
       //getChars将拼接字符串赋值到char[]中
        str.getChars(0, len, value, count);
        count = newCount;//更新char[]所保存的字符串长度
        return this;
    }

  可知,用StringBuilder拼接字符串时,其实是在底层创建了一个char[]数组,然后通过char[]把要拼接的字符串添加到char[]而已。最后通过toString()生成最终拼接结果时就是通过  return new String(char[]) 实现的。

           从上面(其实应该说是五种,+ 分为字符串常量的拼接和变量的拼接两种)的字符串拼接来看,除了字符串常量的拼接是返回拘留字符串的地址外,其他四种(str1+str2、str1.concat(str2)、builder.append(str1).append(str2)、buffer.append(str1).append(str2))都是使用了StringBuilder,或者说是StringBuilder的父类的拼接方法来做的——创建一个char数组,把需要拼接的内容先存进char数组,最后通过char数组创建新的String对象返回。

            造成三者性能差别的主要原因是:

            用String的 + 累加拼接字符串变量时,每拼接一个就会创建一个StringBuilder,并通过append()方法拼接,然后返回一个新的String对象。然后再继续拼接下一个变量。这样就会导致重复创建StringBuilder对象,性能低下。用 concat() 累计拼接时,则每两个字符串拼接都会创建一个 char[] 进行内容拼接并返回一个新的String对象作为结果,重复调用concat()会导致重复创建char[]和新String对象,性能低下。

            StringBuilder在调用toString()之前都不会创建拼接结果,并且底层的char数组会自动扩容,一直到拼接字符串全部存入char数组后,调用toString()时才创建新的String对象并返回,这样就避免了重复创建,效率提高。

            StringBuffer则因为使用了syncrhoized对append()进行了加锁,所以导致性能稍微低于StringBuilder

 

 

注意:

(1)String str = new String("abc")创建了多少个对象?

什么叫“创建了”?什么时候创建了什么? 

人混淆的地方就是这里,这段代码在运行期间确实只创建了一个对象,即在堆上创建了"abc"对象。而为什么大家都在说是2个对象呢,这里面要澄清一个概念  该段代码执行过程和类的加载过程是有区别的。在类加载的过程中,确实在运行时常量池中创建了一个"abc"对象,而在代码执行过程中确实只创建了一个String对象。

    因此,这个问题如果换成 String str = new String("abc")涉及到几个String对象?合理的解释是2个。

        解释:一个是字符串字面量"abc"所对应的、驻留(intern)在一个全局共享的字符串常量池中的实例,另一个是通过new String(String)创建并初始化的、内容与"abc"相同的实例

         或者是:在运行时涉及几个String实例?(不涉及编译时期)是一个

(2)StringBuffer常见的方法:,StringBuilder的方法相同。

1,public StringBuffer append(String s)         将指定的字符串追加到此字符序列。

2,public StringBuffer reverse()             将此字符序列用其反转形式取代。

3,public delete(int start, int end)         移除子字符串中的字符(可以删除一个字符,也可以不删除一个字符,也可以是字符串)

4,public  deleteCharAt(int i)           删除某一特定位置的字符,也可以用方法三完成。

5,public insert(int offset,  String str)         将 string参数的字符串表示形式插入此序列中,这里的参数可以是任何类型的。int,double,数组...... ...跟append方法一样后面的参数可以是任何类型的数据。

6,replace(int start, int end, String str)     使用给定 String 中的字符替换字符串中的某段字符。

7,void setCharAt(int index, char ch)       修改某一特定位置的字符。注意参数只能是chat。

8,void setLength(int newLength)             设置字符序列的长度。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

深入解析Java中的String、StringBuilder与StringBuffer:特性、区别与最佳实践 在Java编程中,字符串处理是最基础也是最频繁的操作之一。Java提供了三种主要的字符串处理类:String、StringBuilder和StringBuffer。虽然它们都能处理字符串,但各自的设计理念、性能特征和适用场景却大不相同。本文将全面剖析这三者的区别,帮助开发者做出明智的选择。 阅读详情

相关推荐

Java中String、StringBuffer与StringBuilder的深度解析与应用

直接继承自,这是一个被final修饰的抽象类,定义了所有可变字符序列的基本操作框架。该类封装了底层字符数组()、当前有效字符长度(int count)以及一系列用于追加、插入、删除等操作的核心方法。// ...而的结构如下所示:int count;// 核心方法省略这一设计的关键在于:将可变性逻辑集中管理,避免重复实现。无论是还是,它们都复用了相同的存储结构和大部分算法逻辑,唯一的区别体现在方法是否加锁。例如,在方法中,调用的是父类的。

weixin_35019679的博客 840

java 字符串连接(+、concat、StringBuffer/StringBuilder)效率比对

三种方法 java字符串连接有三种方法: 用加号+连接,如:"abc"+"bcd" String对象的concat方法,如:"abc".concat("bcd") 以及StringBuffer或StringBuilder类,如: StringBuilder stringBuilder = new StringBuilder ("abc"); stringBuilder.append ("bcd"); stringBuilder.toString (); StringBuffer和StringB

szw-yunie的博客 1612

将AAL图谱对应到Yeo7大网络中【原理,代码分析】

本文介绍了将AAL2图谱映射到Yeo7大功能网络的方法。通过整合皮层(Yeo2011)、小脑(Buckner2011)和纹状体(Choi2012)三个区域的功能网络图谱,采用投票机制确定每个AAL区域的网络归属。具体步骤包括:1)统计每个AAL区域体素在各网络图谱中的分布;2)选择体素数量最多的网络作为该区域的最终标签。该方法实现了从解剖结构到功能网络的映射,可获得120个AAL区域对应的7大功能网络标签。

yes666666的博客 2203

【Java字符串】String、StringBuilder和StringBuffer

前言 本人使用的jdk8。 String String是Java中最常用的类,这个类并不是Java基础类型,它的底层是char数组实现的,然后提供了众多操作这个char数组的方法。String类是final的,即不能被继承的,String中的字符串也是不可变的。 1. 底层实现 下面是String类的一点注释介绍:所有的字符串字面量(string literals)如“abc”,都被实现...

奋进的小白粥 274

SpringBoot项目整合达梦数据库(MYSQL 转换 达梦数据库)

注意:当迁移过程中出现下面问题时,如有触发器或者外键,需要先关掉触发器和外键,然后进行迁移,不然会导致迁移失败。(2)dm.ini修改【#compatibility】的【COMPATIBLE_MODE】=4。3、添加用户:如果导入的DM数据库需要和MYSQL的用户一样,添加ROOT用户。方法一:服务器配置:设置系统兼容性(DM控制台工具),兼容MySQL。服务器配置又该有两种方式:①DM控制台工具修改;MYSQL的数据表转换成DM的数据表时,点击转换按钮。在这里操作:MYSQL数据库迁移至DM数据库。

m0_74824635的博客 2013

Win11系统重装全记录:从备份Office激活到搞定RAID阵列,我的微星笔记本复活记

本文详细记录了Win11系统重装的完整过程,从数据备份到RAID阵列配置,特别针对微星笔记本的特殊硬件驱动问题提供了解决方案。文章涵盖了Office激活状态备份、BIOS设置、驱动安装顺序等关键步骤,帮助用户顺利完成系统重装并优化性能。

weixin_31421613的博客 309

【Java基础常用类】String、StringBuffer、StringBuilder用法与注意事项

List item

VanGotoBilibili的博客 1万+

基于线性约束最小方差准则(LCMV)的自适应波束形成算法的matlab仿真

波束形成(BeamForming)通过对多路麦克风(常为多路全向麦)信号进行合并,抑制非目标方向信号,增强目标方向信号;进而能够实现对特定方向的聚焦拾音,能够有效提高接收信号的信噪比,也有起到降噪的作用。基本原理是波的干涉:通过调整不同阵列单元信号之间的参数,使得某些角度的信号增强,而另一些角度的信号相互抵消,例如下图中来自±45°的输入信号未被增强,而在0度方向的输入信号同相位叠加后被增强。为了将窄带波束形成扩展至宽带,可以使用频域LCMV波束形成器。

平时工作较为繁忙,私信消息一般晚上回复,谢谢大家~~ 761

String——存储(源码详解)

1 String 源码介绍 public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ pri

一个搬砖工人 264

我的PCB设计经验总结及最容易犯错的100例之二B07

本文总结了PCB设计中的常见错误及解决方法。作者通过记录自身及他人的设计失误,系统归纳了高频、隐蔽且致命的问题,如电容中间穿线、高速信号跨分割、锐角布线等。重点提出从错误中提炼规律,建立分类案例库,并开发自动化检查工具的方法。案例涵盖高速信号处理、电源设计、EMC防护等关键领域,强调通过原理理解和实践验证提升设计质量。文章建议工程师建立个人错误数据库,从被动纠错升级为主动预防,最终形成系统化的设计方法论,提高PCB一次成功率。

启芯硬件的博客 82

(12)单相降压自耦变压器的等效电路和仿真模型

本文根据电机学基本原理,从单相双绕组变压器的接线方式出发,建立基本方程并导出T型等效电路。然后将双绕组变压器演变成一种降压自耦变压器,详细地建立起单相降压自耦变压器的数学模型以及导出相对应的等效电路,最后用Matlab/simulink的simscape元件库元件建立了基于单相自耦变压器的T型等效电路的仿真模型。用实例仿真验证了本文工作的正确性。

weixin_45670943的博客 1046

Java中String str1 = “Java”和String str2 = New String(“Java”)两种声明方式之间的区别

我们知道,对象间的比较可通过“==”运算符和“equals()”方法两种方式进行,“==”运算符用于比较两个对象的内存地址的值是否相等,而“equals()”方法则是用比较两个对象的内容是否一致。在这里,str1与str3相等,说明str1和str3是指向同一个内存空间的。如下图所示:如下图所示:...

SmartAnt_5658的专栏 6540

微调实操一: 增量预训练(Pretraining)

《微调入门篇:大模型微调的理论学习》我们对大模型微调理论有了基本了解,这篇结合我们现实中常见的场景,进行大模型微调实操部分的了解和学习,之前我有写过类似的文章《实践篇:大模型微调增量预训练实践(二)》利用的MedicalGPT的源码在colab进行操作, 由于MedicalGPT代码比较难以理解,而且模型只能从hugging face上下载,对于一些国内服务器无法访问,我重构了代码,让训练代码更有可读性,并参考LLAMAFactory的项目,增加了modelscope上下载模型,轻松在国内服务器运行.

youbingchen的博客 6992

java常用方法还有String、StringBuilder、StringBuffer底层解析

记录Java方法常用 String类常用的方法一: char charAt(int index) 返回字符串中index位置处的字符,index从0开始 int compareTo(String anotherString) 比较当前字符串与anotherString字符串的大小。当前字符串大,则返回正整数;当前字符串小,则返回一个小于0的整数;两者相等,则返回0 int compareToIgnoreCase(String anotherString) 比较两个字符串的大小,比较时,忽略大小写;返回结果和

HolleDream的博客 191

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

java stringbuffer原理_String,StringBuilder,StringBuffer 实现原理解析

定义:从jdk1.5开始提供的新的封装字符串的类,StringBuilder,其字符串拼接操作的效率远远高于 String。Java里面提供了String,StringBuffer和StringBuilder三个类来封装字符串简介:我们知道字符串其实就是由若干个字符线性排列而成的,可以理解为字符数组Array,那么既然是数组实现的,那就需要考虑到数组的特性,数组在内存中是一块连续的地址空间块,即在...

weixin_36411269的博客 529

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Java String、StringBuffer、StringBuilder类解析

分析了String类的特点,常用方法,还有StringBuffer类和StringBuilder类的源码分析,还有三者的效率对比。

TheAnnoyingDog的博客 646

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

从源码解析Java中String、StringBuilder、StringBuffer的区别

下面给大家从JDK的源码解析下Java中String、StringBuilder、StringBuffer的区别。 (1)String类的类定义如下:    public final class String implements java.io.Serializable, Comparable, CharSequence       这是JDK针对String类定义的源码。看到标红

SimonL的博客 344

理解java String,深入解析StringBuffer和StringBuilder的区别

要理解 java中String的运作方式,必须明确一点:String是一个非可变类(immutable)。什么是非可变类呢?简单说来,非可变类的实例是不能被修改的,每个实例中包含的信息都必须在该实例创建的时候就提供出来,并且在对象的整个生存周期内固定不变。java为什么要把String设计为非可变类呢?你可以问问 james Gosling :)。但是非可变类确实有着自身的优势,如状态单一,对象...

weixin_30394251的博客 79

Java中的String、StringBuilder以及StringBuffer解析

相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问到的地方,今天就来和大家一起学习一下String、StringBuilder和StringBuffer这几个类,分析它们的异同点以及了解各个类适用的场景。下面是本文的目录大纲:   一.你了解String类吗?   二.深入理解String、StringBuffer、StringBuilder   三.不同场景...

MarkZP 518

Java 字符串全解析:String、StringBuilder 与 StringBuffer 区别详解

特性String可变性不可变可变可变线程安全是否是性能最低最高中等推荐场景常量、Map key单线程拼接、大量构建多线程日志、拼接。

2302_79797878的博客 1160

深入理解Java字符串处理三剑客:String、StringBuffer、StringBuilder全面解析

场景推荐类理由静态常量String利用字符串池优化内存单线程动态拼接无锁设计性能最优多线程安全操作同步方法保障线程安全高频修改的小字符串char[]直接操作数组避免对象开销(如密码处理)通过深入理解三者的底层机制,开发者可以在性能与安全之间做出精准权衡。建议在代码审查时重点关注字符串处理方式,避免因滥用String导致内存泄漏或性能瓶颈。

因为热爱,所以付出 1024

java基础解析系列(一)---String、StringBuffer、StringBuilder

java基础解析系列(一)---String、StringBuffer、StringBuilder 前言:本系列的主题是平时容易疏忽的知识点,只有基础扎实,在编码的时候才能更注重规范和性能,在出现bug的时候,才能处理更加从容。 我的博客目录 这是我的博客目录,欢迎阅读 String ==问题 String s6=new String("jiajun"); ...

anzhuan3270的博客 172

java--String、StringBuilder、StringBuffer的解析和比较?

一、String的解析 1.String的含义 ①String是不可以被继承的,String类是final类,String类是由char[]数组来存储字符串。 ②String是不可变的字符序列,如果存储abc则在字符串常量池中开辟长度固定为3的字符数组,无论怎么改变均会产生新的实例。 2.String的方法 由上图可知String的方法,不是在原有字符串的基础上进行修改的,都是new出了新的实...

weixin_30263073的博客 358

解析Java中的String、StringBuilder、StringBuffer类(一)

引言 String 类及其相关的StringBuilder、StringBuffer 类在 Java 中的使用相当的多,在各个公司的面试中也是必不可少的。因此,在本周,我打算花费一些时间来认真的研读一下 String、StringBuilder、StringBuffer类 的相关代码。 String的不可变性 这个特性是 String 相当重要的一个特性,为了深入理解,我直接贴上其源代码...

100
上一篇: Java内存分配即数据的存储
下一篇: Java集合框架
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值