String类的学习笔记(下):字符串拼接以及StringBuilder和StringBuffer的学习

news/2025/2/22 2:02:05/

本文介绍了String类对字符串进行拼接的方法 和拼接字符串的效率分析 以及能对字符串内容进行修改的StringBuilder和StringBuffer类其常用方法和区别 , 最后介绍了两个字符串经典面试题

StringBuilder和StringBuffer的学习

  • 一.String类概括
  • 二.StringBuilder和StringBuffer
    • 1.字符串拼接
    • 2.StringBuilder和StringBuffer常用方法和区别
    • 3. 面试题:以下代码共创建多少个对象?
    • 4.面试题: String 、StringBuilder和StringBuffer的异同
  • 三.总结

一.String类概括

1.String常用方法学习->2.String的不可变和字符串常量池->StringBuilder和StringBuffer

String类是Java中用来描述操作字符串的类
上两篇博客介绍了介绍了常用的方法,以及String的特性:String内容是不可变的以及字符串常量池,感兴趣的可以去看看…

二.StringBuilder和StringBuffer

StringBulder和StringBuffer是和String一样都是对字符串进行操作的类
而学了String后知道,String内容是不可变的,对String的内容进行修改都会创建一个新的字符串返回

而创建新的String对象比原字符串修改所耗费的时间空间更多,效率低很多

因此,java中提供的StringBuilder和StringBuffer是专门用来对字符串进行原地修改的类,并且它们都可以和String类之间进行相互转换

在这里插入图片描述
在这里插入图片描述
通过源码看到 这两个类的方法大致都相同,且都extends继承了AbstractStringBuilder类

在这里插入图片描述
而AbstractStringBuilder类 底层是存在一个value 数组引用和count变量的,其没有被private和final修饰 能够在StringBuilder和StringBuffer中访问到

value数组即维护的是字符串内容 , 而count记录的是value内有效的字符个数即真正的字符串长度

(因为value指向的字符数组长度是当前存放字符串的空间,还有预留的空间用来新增字符等, count记录的才是字符串真正的长度)

由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilder和StringBuffer类。这两个类大部分功能是相同的

1.字符串拼接

在String方法中提供concat和join方法 可以使字符串之间进行拼接

在这里插入图片描述

concat是成员方法,使一个字符串对象内容与另一个字符串对象进行连接成一个新的字符串对象返回
在这里插入图片描述

join是静态成员方法, 方法第一个参数 是连接的分隔字符串, 后续2~n个是用来连接的字符串, 会将其拼接在一起 用一个参数做分隔(分隔连接的每段字符串,如果只有一段则不显示分隔符),最后返回此拼接的字符串对象

在这里插入图片描述

但上面这些方法并不具备将其他数据类型的数据拼接进字符串的功能因此使用这些方法还要拼接其他非String类型的数据还要将其先转换为字符串再进行拼接

而在Java中,String类型 用 + 连接 String字符串数据和任意类型数据 都可以使其简单快捷直接拼接为一个新字符串对象
示例:

public static void main(String[] args) {System.out.println("12"+3);System.out.println(3+"12");System.out.println(1+2+"12");System.out.println("12"+1+2);System.out.println(false+"12"+true);//代码输出结果是什么?}

在这里插入图片描述
字符串类型数据和任何数据类型数据 之间使用+运算,都可以拼接成一个新的字符串对象,

但注意要运算符的优先级, 1+2+“12” 是先计算1+2 结果为3 再3+“12"拼接成字符串"312”

“12”+1+2,是先"12"+1拼接成字符串"121" 再+2 拼接成字符串"1212"

boolean类型数据可以参与字符串拼接

“”+12 可以使 12数字拼接为字符串"12"

通过+号可以快速实现字符串拼接,这种用法很方便让我们使基本数据类型快速变为字符串类型

StringBuilder和StringBuffer也可以实现字符串拼接, 需要调用其内部的append方法:

public static void main(String[] args) {StringBuilder stringBuilder=new StringBuilder();stringBuilder.append(1+2);stringBuilder.append(12);System.out.println(stringBuilder);stringBuilder.append(3);System.out.println(stringBuilder);stringBuilder.append(false);System.out.println(stringBuilder);}

在这里插入图片描述

可以看到通过StringBuilder对象 使用其append方法可以将任意数据类型拼接成一个字符串
在这里插入图片描述
而append方法内部最后返回的都是StringBuilder对象本身,并没有创建新对象…

从运行效率上String类型使用+和其他数据拼接 和StringBuiler以及的append方法哪种更好?

此时可以使用Java内一种计算内部运行时间的方法System.currentTimeMillis()采取差值运算, 来分别测试这三个的运行时间…
示例:

public static void main(String[] args) {long start = System.currentTimeMillis();  // 计算当前内部运行时间String s = "";for(int i = 0; i < 10000; ++i){s += i;                             //字符串类型 加任意基本数据类型 都会拼接成一个新字符串再给s引用接收}   // 每+=一次 会额外创建三个对象long end = System.currentTimeMillis();System.out.println(end - start);start = System.currentTimeMillis();StringBuffer sbf = new StringBuffer("");  // 需要加锁解锁for(int i = 0; i < 10000; ++i){sbf.append(i);                     //对字符串内的数组进行操作 不会创建额外字符串}end = System.currentTimeMillis();System.out.println(end - start);start = System.currentTimeMillis();StringBuilder sbd = new StringBuilder();for(int i = 0; i < 10000; ++i){sbd.append(i);                 //对字符串内的数组进行操作 不会创建额外字符串}end = System.currentTimeMillis();System.out.println(end - start);}

在这里插入图片描述
通过运行结果可大概估计:拼接效率:String<StringBuffer<StringBuilder

为什么String类型使用+进行字符串拼接效率比StringBuilder和StringBuffer慢很多?

通过 javap -c 字节码文件 反汇编此文件, 能看到使用+号底层做了些什么事
在这里插入图片描述
使用+进行拼接, 本质上是先new了一个StringBuilder对象,然后调用append方法将s字符串追加进去,再调用append 将i 追加进去, 最后调用了toString方法返回~

在这里插入图片描述
而StringBuilder重写了toString方法,其作用是 实例一个新String对象,
将StringBuilder继承的AbstractStringBuilder的value数组引用指向的数组 和 ,0 ,count作为参数传参调用其构造方法,

作用是 创建一个String对象 其内容是 value指向的数组对象 0~count之间的内容 (注意:String内的value是指向的新value数组)

可见:使用+号拼接字符串,在底层是使用了StringBuilder对象的append方法,最后返回的也是一个新String对象…

那在上述代码中, 使用for循环通过+号拼接了10000个i, 每次拼接都会创建一个StringBuilder对象和String对象, 可见完成此操作需要new如此多的对象,而且还要回收掉未被指向的String对象, 消耗非常大

而直接实例StringBuilder对象通过append追加字符串内容, 全部追加完成后最后只需要将StringBuilder对象转换String对象 进行一次操作即可, 在此操作里只额外实例化了两个对象, 开销比+号少的多

故:在使用大量字符串追加操作时, 不建议使用+号操作符进行拼接, 其性能远远低于用StringBuilder进行append拼接, 而使用StringBuilder效率比其他拼接方法效率更高

(“1”+“2” 字符串常量用+号拼接不会进行上述append在底层直接看成"12"字符串)

2.StringBuilder和StringBuffer常用方法和区别

StringBuilder和StringBuffer都能对字符串进行修改, 其内部大部分方法也是相同
以下是一些常用的其内能对字符串内容进行修改的方法如:

方法作用
append()在尾部追加,相当于String的+=,可以追加:boolean、char、char[]、double、float、int、long、Object、String、StringBuff的变量
void setCharAt(int index,char ch)将index位置的字符设置为ch
insert(int offset, String str)在offset位置插入:八种基类类型 & String类型 & Object类型数据
deleteCharAt(int index)删除index位置字符
delete(intstart, int end)删除[start, end)区间内的字符
replace(intstart, int end, String str)将[start, end)位置的字符替换为str
reverse()将字符串进原地逆置
toString()将内容以String对象形式返回

以上是StringBulider和StringBuffer常用到的对字符串内容进行修改的方法,其内还有一些和Stirng类一样的方法如 indexOf(),具体可自己去了解

既然大部分方法都是相同的,那这两个类的具体区别在哪?

因为String类不能对字符串进行修改,其设计可以使线程更安全,每个线程对方法的调用都是创建新字符串对象, 而 StringBuilder能对字符串内容进行修改,那就会导致多个线程同时调用一个方法会产生一些问题… 此时正是要解决这个线程不安全的问题

在这里插入图片描述
在这里插入图片描述
通过源码可以看到,StringBuffer内大部分的方法都有synchronized(同步) 关键字修饰 ,被此关键字修饰的方法即为同步方法, 其是线程安全的, 表示在多线程情况下, 不同线程同时调用这个方法时会将其上锁,同一时间只能有一个线程执行此方法,其它线程只能等待执行完这个方法解锁后才能一一执行此方法

而在上面StringBuffer 和StringBuilder 对象 对10000个i进行拼接时, StringBuilder比其效率高一点,也是因为 StringBuffer 执行方法时 还要 进行加锁解锁操作,此也是要消耗资源的…

故StringBuffer类用在多线程情况下,对字符串对象进行修改 而StringBuilder用在单线程情况下

3. 面试题:以下代码共创建多少个对象?

 public static void main(String[] args) {String str=new String("123");  // 创建多少个对象String str1=new String("1"+"2")+new String("3"); //创建多少个对象
//以上程序在运行时字符串常量都是第一次出现字符串常量池并不存在程序中的常量字符串}

在程序运行时,并 str代码 一个"123"对象并存放在字符串常量池里,new String()一个对象; 最后 创建了两个String对象

str1处 首先new了一个StringBuilder对象 再 new String() 一个对象 , “1”+“2” 底层直接编程成"12" 是一个String对象 , 再被拼接到StringBuilder中, 然后在new String对象, 然后"3"一个对象 , 再被拼接到StringBuilder对象中 , 最后 StringBuilder调用了toString又new了一个String对象 返回 , 最后 new了1个StringBuilder对象和五个String对象

注意str1最后接受的字符串内容是123 但是其和字符串常量池中的"123" 是不同的
字符串常量池是在编译时将其字符串常量"123"存放进去的, 而str1接受的是后续拼接出来的字符串123

在这里插入图片描述

4.面试题: String 、StringBuilder和StringBuffer的异同

三者都是用来描述操作字符串的类

String类的内容是不可变的所有对String内容进行修改的操作都是创建新String对象

,StringBuilder和StringBuffer的内容都是可变的,常用来对字符串内容进行频繁修改时使用,

StringBuffer与StringBuilder大部分功能是相似的

StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作

三.总结

本文介绍了字符串拼接的方法 (String的成员方法concat和类成员方法join +号运算符拼接 StringBuilder和StringBuffer的append拼接 )以及各种拼接方法的效率 和底层反汇编分析, StringBuffer和StringBuilder的大部分对内容进行修改的方法,和其不同点, 以及两大字符串方面的面试题 及其分析

在这里插入图片描述


http://www.ppmy.cn/news/96389.html

相关文章

第一节 Python 顺序结构

1 . Python 介绍 1.1 Python是什么 Python是一种高级编程语言,具有简单易学、功能强大、可扩展性好等特点,是目前广泛应用于Web开发、数据分析、人工智能等领域的编程语言之一。 Python的历史可以追溯到1989年,当时在荷兰的Guido van Rossum开发了这种语言,Guido最初设计P…

Arduino学习

物联网学习资料 《arduino程序设计基础》陈吕洲 北京航空航天大学出版社 半颗心脏博客导航一站式搜索(所有博客的汇总帖) Ai-Thinker 安信可科技 github 半颗心脏 | 徐宏 蓝牙技术 蓝牙网关【【智能家居】入门攻略二&#xff01;啥是网关&#xff1f;蓝牙、zigbee协议详…

【Java零基础入门篇】第 ③ 期 - 面向对象编程(一)

【Java零基础入门篇】第 ③ 期 - 面向对象编程&#xff08;一&#xff09; 博主&#xff1a;命运之光 专栏&#xff1a;Java零基础入门 理解面向对象三大主要特征&#xff1b; 掌握类与对象的区别与使用&#xff1b; 掌握类中构造方法以及构造方法重载的概念及使用&#xff1b;…

YUM安装LNMP架构配置命令与搭建论坛

LNMP架构配置命令与搭建论坛 LNMP简介安装须知安装 Nginx配置yum源yum安装nginx并查看版本号开启服务并且设为开机自启 安装 MySQL 5.7 (mariadb)移除软件包下载安装mysql安装MySQL报错问题解决方案&#xff1a; 开启服务并设为开机自启在日志文件中找出root用户的初始密码登录…

【趣味题目】不用加减乘除做加减乘除运算

不用加减乘除做加减乘除运算 预备知识做加法做减法做乘法做除法|取模 预备知识 这类题目我选择使用位运算&#xff0c;需要了解到&#xff1a;两个数异或&#xff08;a^b&#xff09;结果是忽略进位的结果&#xff1b;两个数相与&#xff08;a&b&#xff09;<<1结果…

横向移动-传递攻击atschtasks

横向移动就是拿下对方一台主机后&#xff0c;以拿下的那台主机作为跳板&#xff0c;对内网的其他主机再进行后渗透&#xff0c;拿到其他内网主机的权限的过程。叫做横向移动。横向移动的主要目的就是扩大战果。 传递攻击主要建立在明文和hash值获取基础上进行攻击。 at和scht…

AI歌手是否会取代流行歌手成为主流?

随着科技的飞速发展&#xff0c;人工智能已经渗透到了我们生活的方方面面。在音乐领域&#xff0c;AI歌手逐渐崭露头角&#xff0c;引发了人们对于未来音乐产业发展的讨论。 那么&#xff0c;AI歌手是否会取代流行歌手成为主流呢&#xff1f;本文将从以下几个方面进行分析&…

CAPL(vTESTStudio) - CAPL控制RS232继电器

目录 为什么要使用CAPL控制继电器? 一、RS232继电器选择 二、继电器通信协议