【java】关于String、StringBuffer和StringBuilder的那些事

   在之前的文章中我们曾简单介绍过String这个引用类型变量,其实它还有许多特性,还有StringBuffer和StringBuilder这两个方法在字符串操作中也有非常重要的地位,接下来就由小编带大家梳理一下吧👊

ef22313ff90042009f01c78f367a4671.jpg

 

目录

一、String

1、构造方法

2、字符串的不可变性

3、字符串的比较

4、 String的常用方法:

二、StringBuider和StringBuffer

1、字符串的拼接

2、StringBuider与StringBuffer

总结

 


 

一、String

1、构造方法

String类提供的构造方式非常多,常用的就以下两种:
public static void main(String[] args) {// 使用常量串构造String s1 = "hello";System.out.println(s1);// 直接newString对象String s2 = new String("hello");System.out.println(s1);}

注意:

1、String是引用类型,内部并不存储字符串本身

2. 在Java中“”引起来的也是String类型对象
那么这两种对象的存储方式有什么区别呢?
1c4580b6cc564e07b96a52f3b3b7382d.png

在s1使用常量串构造时,会直接在字符串常量池中创建字符串,在栈中直接存储字符串在字符串常量池中相应的位置

在s2通过new String对象的方式实例化字符串时,由于其字符串内容与s1一致,不会在常量池中创建新的对象,此时字符串对象存储在堆中,在堆中存储了对应字符在常量池中的位置

这样做有什么好处呢?就是所有的字符只用在字符串常量池中创建一次就行了,后续创建的相同的字符串只需引用对应的位置即可,大大提高了空间资源的利用效率

 

2、字符串的不可变性

String是一种不可变对象. 字符串中的内容是不可改变。字符串不可被修改,是因为:
1. String 类在设计时就是不可改变的, String 类实现描述中已经说明了
以下来自JDK1.8中String类的部分实现:
public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {private final char value[];

可以看出:

1. String类被final修饰,表明该类不能被继承
2. value被final修饰,表明value自身的值不能改变,即不能引用其它字符数组,但是其引用空间中的内容可以修改。
2. 所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象

如在以下代码中:

String s1="hello";
String s2="hello";
s1="world";

5203648de539461c880b43d9a3c67fed.png

s1发生改变时,s2并不会改变指向,s1会重新分配内存地址进行赋值

String字符串具有不可变性,当字符串重新赋值时,不会在原来的内存地址进行修改,而是重新分配新的内存地址创建新的对象进行赋值

注意:

字符串不可变不是因为其内部保存字符的数组被final修饰了,因此不能改变。 不是因为String类自身,或者其内部value被final修饰而不能被修改。
final 修饰类表明该类不想被继承, final 修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内 容是可以修改的

 

3、字符串的比较

 

1. == 比较是否引用同一个对象
public static void main(String[] args) {int a = 10;int b = 20;int c = 10;// 对于基本类型变量,==比较两个变量中存储的值是否相同System.out.println(a == b); // falseSystem.out.println(a == c); // true// 对于引用类型变量,==比较两个引用变量引用的是否为同一个对象String s1 = new String("hello");String s2 = new String("hello");String s3 = new String("world");String s4 = s1;System.out.println(s1 == s2); // falseSystem.out.println(s2 == s3); // falseSystem.out.println(s1 == s4); // true
}
注意:对于内置类型,==比较的是变量中的值;对于引用类型==比较的是引用中的地址。
2. boolean equals(Object anObject) 方法:按照字典序比较
字典序:字符在ASCII码中的顺序
public boolean equals(Object anObject) {// 1. 先检测this 和 anObject 是否为同一个对象比较,如果是返回trueif (this == anObject) {return true;}// 2. 检测anObject是否为String类型的对象,如果是继续比较,否则返回falseif (anObject instanceof String) {// 将anObject向下转型为String类型对象String anotherString = (String) anObject;int n = value.length;// 3. this和anObject两个字符串的长度是否相同,是继续比较,否则返回falseif (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;// 4. 按照字典序,从前往后逐个字符进行比较while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}}

 

3、int compareTo(String s) 方法 : 按照字典序进行比较
与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。具体比较方式:
1. 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
2. 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值

 

public static void main(String[] args) {String s1 = new String("abc");String s2 = new String("ac");String s3 = new String("abc");String s4 = new String("abcdef");System.out.println(s1.compareTo(s2)); // 不同输出字符差值-1System.out.println(s1.compareTo(s3)); // 相同输出 0System.out.println(s1.compareTo(s4)); // 前k个字符完全相同,输出长度差值 -3
}

 

4. int compareToIgnoreCase(String str) 方法:与compareTo方式相同,但是忽略大小写比较
public static void main(String[] args) {String s1 = new String("abc");String s2 = new String("ac");String s3 = new String("ABc");String s4 = new String("abcdef");System.out.println(s1.compareToIgnoreCase(s2)); // 不同输出字符差值-1System.out.println(s1.compareToIgnoreCase(s3)); // 相同输出 0System.out.println(s1.compareToIgnoreCase(s4)); // 前k个字符完全相同,输出长度差值 -3
}

4、 String的常用方法:

6beff4d7f2f04770946eefe5118cf518.png

 

 


 

二、StringBuider和StringBuffer

1、字符串的拼接

让我们先来看一下下面这个问题:

public static void main(String[] args) {String s1 = "abc";s1=s1+"def";System.out.println(s1); }
//以上代码创建了几个对象?

答案是三个

b8902bd75d364a9f878f3cc7fa22c3be.png

        首先语句“String s1 = new String("abc");”会在字符串中创建一个对象"abc",在执行语句"s1=s1+"def";"时,会先创建一个对象“def”,然后在创建两个对象相加后的结果“abcdef”

这时我们发现看似简单的一个拼接操作,竟然需要创建三个对象,其效率可想而知是非常低下的,因此我们在平时应用中一般会避免这样直接通过“+”进行字符串的拼接。那么我们该怎么去拼接呢?这时候我们就要介绍StringBuider和StringBuffer了

 

2、StringBuider与StringBuffer

由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilder和StringBuffer类。他们的底层原理与String类似,都是通过数组来完成对字符串的存储,其默认长度为16,当实例化一个StringBuider对象时,会根据创建字符串的长度来初始化内存,数组的内存为“创建字符的长度+16”,即在进行修改字符串的操作时有16个字符的空间可供操作,在对字符串进行修改时,会自动检测当前char数组是否装的下,如果超出数组范围,会对char数组进行扩容。
扩容机制:创建一个新的char数组对象,其长度一般为原数组的两倍,接着判断是否足够存储新的字符串,如果不够再进行扩容,以此类推,直到创建的数组足够存储新的字符串为止。然后将新字符串的内容存储到新数组,最后将指针指向新的数组

常用方法:

e68bd5e063b241cb83c0df47881a7f84.png

 

String和StringBuilder最大的区别在于 String 的内容无法修改,而 StringBuilder 的内容可
以修改。频繁修改字符串的情况考虑使用StringBuilder
注意:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:
  • String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
  • StringBuilder变为String: 调用toString()方法
【面试题】String、StringBuffer、StringBuilder的区别
  • String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
  • StringBuffer与StringBuilder大部分功能是相似的
  • StringBuffer大多数方法都使用了synchronized实现了同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作

 

注意:在单线程的条件下,StringBuilder的运行效率要高于StringBuffer,因此在单线程的情况下一般选用StringBuilder,在多线程的情况下优先选用StringBuffer

 


总结

那么本篇文章就到此为止了,如果觉得这篇文章对你有帮助的话,可以点一下关注和点赞来支持作者哦。作者还是一个萌新,如果有什么讲的不对的地方欢迎在评论区指出,希望能够和你们一起进步✊

b943785dc5844e63b6e407dfda9cc6e3.png

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

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

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

相关文章

分库分表 ——12 种分片算法

目录 前言 分片策略 标准分片策略 行表达式分片策略 复合分片策略 Hint分片策略 不分片策略 分片算法 准备工作 自动分片算法 1、MOD 2、HASH_MOD 3、VOLUME_RANGE 4、BOUNDARY_RANGE 5、AUTO_INTERVAL 标准分片算法 6、INLINE 7、INTERVAL COSID 类型算法 …

网络加速器数据可视化大屏:极速网络新体验从这里开始

在信息爆炸的时代&#xff0c;网络已经成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;网络速度慢、不稳定等问题时常困扰着我们&#xff0c;让许多重要的工作和学习进度受到严重影响。 网络加速器数据可视化大屏集数据分析、可视化展示于一体&#xff0c;它不仅能…

docker--部署 (超详版) (五)

环境准备&#xff1a;docker&#xff0c;mysql&#xff0c;redis&#xff0c;镜像&#xff0c;nginx 把虚拟机打开&#xff0c;连接xshell&#xff0c;参考博客&#xff1a; https://blog.csdn.net/m0_74229802/article/details/136965820?spm1001.2014.3001.5501 一&#x…

GoogLeNet

文章目录 Inception块GoogLeNet模型 Inception块 在GoogLeNet中&#xff0c;基本的卷积块被称为Inception块,如下图所示&#xff1a; Inception块由四条并行路径组成。 前三条路径使用窗口大小为1x1,3x3和 5x5的卷积&#xff0c;从不同空间大小中提取信息。中间的两条路径在输…

SambaNova 芯片:深入解析其架构和高性能秘诀

SambaNova——一家总部位于帕洛阿尔托的公司已经筹集了超过10亿美元的风险投资&#xff0c;不会直接向公司出售芯片。相反&#xff0c;它出售其定制技术堆栈的访问权限&#xff0c;该堆栈具有专门为运行最大的人工智能模型而设计的专有硬件和软件。 最近&#xff0c;SambaNova…

Kubernetes篇(三)— 资源管理

目录 前言资源管理介绍YAML语言介绍资源管理方式命令式对象管理命令式对象配置声明式对象配置 前言 本章节主要介绍yaml语法和kubernetes的资源管理方式 资源管理介绍 在kubernetes中&#xff0c;所有的内容都抽象为资源&#xff0c;用户需要通过操作资源来管理kubernetes。 …

hcia datacom课程学习(5):MAC地址与arp协议

1.MAC地址 1.1 含义与作用 &#xff08;1&#xff09;含义&#xff1a; mac地址也称物理地址&#xff0c;是网卡设备在数据链路层的地址&#xff0c;全世界每一块网卡的mac地址都是唯一的&#xff0c;出厂时烧录在网卡上不可更改 &#xff08;2&#xff09;作用&#xff1a…

软考 - 系统架构设计师 - 数据流图案例题

阅读以下关于系统数据分析与建模的叙述&#xff0c;在答题纸上回答问题1至问题3。 【说明】 某公司正在研发一套新的库存管理系统。系统中一个关键事件是接收供应商供货。项目组系统分析员小王花了大量时间在仓库观察了整个事件的处理过程&#xff0c;并开发出该过程所执行活动…

Linux shell编程学习笔记45:uname命令-获取Linux系统信息

0 前言 linux 有多个发行版本&#xff0c;不同的版本都有自己的版本号。 如何知道自己使用的Linux的系统信息呢&#xff1f; 使用uname命令、hostnamectl命令&#xff0c;或者通过查看/proc/version文件来了解这些信息。 我们先看看uname命令。 1 uname 命令的功能和格式 …

SSM框架学习——工厂模式、Spring核心容器与Bean

工厂模式、核心容器与Spring Bean 工厂模式 工厂模式是Java中常用的一种设计模式&#xff0c;这种类型的设计模式属于创建型模式。说白了在代码层面就是取消了new的使用。 工厂模式有三种&#xff1a; 简单工厂模式工厂方法模式抽象工厂模式 举个例子&#xff0c;我们去买…

项目:USB键盘和鼠标的复合设备

我们的复合设备使用一个物理设备就可以完成多个功能。 使用复合设备同时完成USB键盘和鼠标功能&#xff0c;它的主要实现方式有两种&#xff0c; 第一个就是我们将多个设备描述符合并成一个&#xff0c;这个相对比较简单&#xff0c;我们只要根据相应的报告描述符处理数据就可…

基于springboot的房屋租赁系统平台

功能描述 流程&#xff1a;房主登陆系统录入房屋信息》发布租赁信息&#xff08;选择房屋&#xff09;》租客登陆系统浏览租赁信息》和房主联系、看房&#xff08;根据租赁信息单的电话线下沟通&#xff09;》房主发起签约&#xff08;生成邀请码&#xff09;》租客登陆系统根…