还搞不清楚String、StringBuilder、StringBuffer?

news2025/4/7 17:54:25

目录

一、String——引用类型,而不是基本数据类型

二、StringBuffer类

三、StringBuilder类        

四、String、StringBuffer、StringBuilder比较

五、String、StringBuffer、StringBuilder的选择


一、String——引用类型,而不是基本数据类型

1.先来看看String继承了哪些类、实现了哪些接口(我的jdk版本是21)

2.从图可以看出String实现了5个接口,然后我们知道每个类都继承了Object类,所以这个就忽略了,我们就来看一下这几个接口的作用。

接口作用
Serializable表示一个类的对象可以被序列化和反序列化(就是可以将一个对象存到网络或者本地中)
Comparable表示String可以比较大小
CharSequence表示一系列字符的接口。它提供了一些方法来处理和访问字符序列
Constableconstable 类型是指其值是常量的类型,这些常量可以在 Java 类文件的常量池中表示
ConstantDesc用于描述常量池中的常量

3.String的特点:

        3.1   String类不能被继承,因为被final关键字修饰。

        3.2   String内部使用private final byte[] value来存储字符串数据。

        注:jdk<=8的版本使用的是char[] 类型来保存的。为什么呢?主要是因为节省内存空间,官方文档有说明:JEP 254: Compact Strings

         简单解释一下:就是我们大多数情况下使用的字符都是英文字符,然后英文字符需要一个字节,如果使用char的话,就会浪费空间(一个char是2个字节,浪费1个字节的空间)。使用byte就不会浪费空间(一个byte是1个字节)。

        3.3    value被final关键字修饰,就说明value不可修改,这里不可修改指的是value所指的地址不能修改,里面的数据还是可以修改的。看图:

        3.4   修改String类型的变量的值,会重新指向常量池的某个字符串常量,下面会单独讲。 

4.创建String的两种方式:

第一种:String str1 = “hello”;      “hello”就是一个常量

第二种:String str2 =  new String("hello");

        区别:方式一 是先从常量池查看是否有"hello"数据,如果有,则直接指向;如果没有则创建,然后指向。str1最终指向的是常量池的某个常量的内存地址。

                  方式二 是先从堆中创建空间,里面维护了value属性,指向常量池的"hello"内存地址。如果常量池没有"hello",则创建;如果有,直接通过value指向。最终str2指向的是堆中的String对象内存地址。

        内存图:

5.当为String类型的变量重新赋值会发生什么?

String str = "hello";

str = "hello world"; 

        5.1   当执行String str = "hello"会发生什么?它首先会去看运行时常量池是否有"hello",如果常量池没有,则要在常量池中创建一个"hello",然后str指向常量池的"hello";如果常量池有,则str直接指向常量池的"hello"。

        5.2   当执行str = "hello world"会发生什么?首先会去看常量池是否有"hello world",如果常量池没有,则要在常量池中创建一个"hello world",然后str指向常量池的"hello world";如果常量池有,则str直接指向常量池的"hello world"。

        总结:可以看出String效率很低,如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率;如果这样的操作放到循环中,会极大影响程序的性能,所以如果我们需要对String做大量修改,就不要使用String。


二、StringBuffer类

1.先来看看StringBuffer继承了哪些类、实现了哪些接口(我的jdk版本是21)

2.从图可以看出StringBuffer实现了4个接口,继承了AbstractStringBuilder类,我们就来看一下Appendable接口作用吧,其它的String已经讲过了,就不讲了。

接口作用
Appendable定义了可以追加字符序列的类

3.StringBuffer的特点

        3.1   StringBuffer也不能被继承,因为被final关键字修饰。

        3.2   StringBuffer内部是使用父类AbstractStringBuilder的成员变量byte[] value来保存字符串数据的

        注:jdk<=8的版本使用的是char[] 类型来保存的。

        3.3   注意byte[] value没有被final关键字修饰,所以StringBuffer是可变的。

        3.4   byte[] value指向的是堆中byte[]对象,而不是指向常量池的某个字符串常量,下面会单独讲。

        3.5   它是线程安全的,内部的方法都用synchronized来修饰。

4.使用StringBuffer

StringBuffer buffer = new StringBuffer("hello");

        代码解释:在堆中创建StringBuffer对象,然后buffer指向该对象,"hello"存在StringBuffer的成员变量value中,value是指向堆的一个byte[]对象,这个byte[]对象的值为"hello"。

        内存图:

5.当为StringBuffer类型的变量重新赋值会发生什么?

StringBuffer buffer = new StringBuffer("hello");

buffer = new StringBuffer("world");

buffer.append(" java");

        当为buffer重新赋值时,就是在堆中重新创建一个StringBuffer对象,然后buffer指向该对象,new StringBuffer("hello");这个对象没有被引用,所以就会被垃圾回收器回收。

        当执行buffer.append(" java")时,它会直接将" java"添加到world后面,所以buffer的内容就变成了"world java"。

6.value的大小为多少呢?

        当调用的是public StringBuffer()时,会初始化大小为16。

        当调用public StringBuffer(int capacity)时,大小为外部设置的值。

         当调用public StringBuffer(String str)时,它先获取字符串的长度,然后进行判断,如果长度小于Integer.MAX_VALUE-16的话,容量就设为length+16;如果长度大于Integer.MAX_VALUE-16的话,容量就设置为Integer.MAX_VALUE(int MAX_VALUE = 0x7fffffff = 2的31次方-1)。

        当调用AbstractStringBuilder(CharSequence seq)时,流程和public StringBuffer(String str)一样。

 7.详细讲解append方法

        首先判断传进来的str是否为null,如果为null,则为当前StringBuffer的内容追加null。但是如果当前容量不够追加null,则会执行方法ensureCapacityInternal(count + 4);进行扩容(它怎么扩容的一会我们在讲),它扩容四个字符,存放null4个字符,例如:

        如果str不为null,则先获取str的长度,然后进行判断是否需要扩容(扩容一会再说),如果需要则ensureCapacityInternal(count + len);扩容已用字符个数加str长度。然后进行复制的方式,进行修改内容,就是先将value的内容复制到一个新的byte[]中,然后将追加的字符添加到byte[]中,最后将新byte[]赋值给value。

        讲讲扩容:将传进来的值和旧容器大小进行比较,如果小于0,则不需要扩容,还能再用;如果大于0,则需要扩容,然后通过复制达到扩容。

 8.StringBuffer是线程安全的!

        它的全部方法都用了synchronized关键字修饰。

9.String VS StringBuffer

  •  String保存的是字符串常量,里面的值不能更改,每次String类的修改,实际上就是修改指向的地址,效率低。
  • StringBuffer保存的是字符串变量,里面的值是可以更改的,每次StringBuffer的更新实际上是直接更新内容(使用append),不用每次更新地址,效率极高
  • String和StringBuffer都是线程安全的,因为String是不可变的,StringBuffer的方法都使用了synchronized关键字修饰。

三、StringBuilder类        

1.先来看看StringBuilder继承了哪些类、实现了哪些接口(我的jdk版本是21)

2.对应接口的作用可以看上面,这里就不一一介绍了。

3.StringBuilder的特点

        3.1   StringBuilder也不能被继承,因为被final关键字修饰。

        3.2   StringBuilder内部是使用父类AbstractStringBuilder的成员变量byte[] value来保存字符串数据的

        注:jdk<=8的版本使用的是char[] 类型来保存的。

        3.3   注意byte[] value没有被final关键字修饰,所以StringBuilder是可变的。

        3.4   byte[] value指向的是堆中byte[]对象,而不是指向常量池的某个字符串常量,下面会单独讲。

        3.5   它是线程不安全的。

4.使用StringBuilder

StringBuilder builder= new StringBuilder("hello");

        代码解释:在堆中创建StringBuilder对象,然后builder指向该对象,"hello"存在StringBuilder 的成员变量value中,value是指向堆的一个byte[]对象,这个byte[]对象的值为"hello"。

        内存图就不画了,和buffer是一样的,大家可以试着去画一下。


四、String、StringBuffer、StringBuilder比较

  • StrignBuffer和StringBuilder非常相似,均代表可变的字符序列,而且方法也一样。
  • String是不可变字符序列,效率低,但复用率高(多个String指向同一个字符串数据)。
  • StringBuffer是可变字符序列,效率较高、线程安全。
  • StringBuilder是可变字符序列,效率最高、线程不安全。

        怎么证明呢?我们来使用代码证明一下:

        解释代码:用循环修改String、StringBuffer、StringBuilder里面的内容,然后看看他们各自耗时多久。运行结果:

        可以看到StringBuilder耗时最短,String耗时最长并且是StringBuffer和StringBuilder的百倍。可以看到在需要更改字符串内容时,String效率很低,会影响程序的性能。StringBuffer之所以会比StringBuilder耗时久一点,是因为它一旦访问append方法,就会先去拿锁,然后进行相应的操作。StringBuilder一旦执行append,就直接进行相应的操作。


五、String、StringBuffer、StringBuilder的选择

  • 如果字符存在大量的修改操作,一般使用StringBuffer 或 StringBuilder
  • 如果字符串存在大量的修改操作,并在单线程的情况,使用StrignBuilder
  • 如果字符串存在大量的修改操作,并在多线程的情况,使用StringBuffer
  • 如果我们字符串很少修改,被多个对象引用,使用String

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

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

相关文章

怎么隐藏搜狗输入法

点击输入法&#xff0c;右键选择更多 点击选项&#xff0c;点击全屏隐藏

《“八股文”之辩:程序员面试与实际工作的纠葛》

在当今的编程世界中&#xff0c;“八股文”成为了一个备受争议的话题。它既是大中小企业面试程序员时的常见问题&#xff0c;又引发了广泛的讨论和思考。那么&#xff0c;“八股文”究竟在实际工作中扮演着怎样的角色呢&#xff1f; “八股文”作为面试的必问内容&#xff0c;…

福建聚鼎:现在装饰画好做吗

在当今社会&#xff0c;随着人们审美情趣的提升和生活品质的改善&#xff0c;家居装饰画已经成为了一种流行的墙面装饰方式。许多人都在思考&#xff0c;现在做装饰画是否是一个好时机? “逆水行舟&#xff0c;不进则退。”在日新月异的市场中&#xff0c;装饰画行业的竞争愈发…

利用 Python 和 IPIDEA:跨境电商与数据采集的完美解决方案

目录 实操案例&#xff1a;利用 IPIDEA 进行数据采集步骤一&#xff1a;注册和获取代理IP步骤二&#xff1a;编写数据采集添加错误处理数据存储到 CSV 文件多线程采集数据 步骤三&#xff1a;处理和分析数据 总结 实操案例&#xff1a;利用 IPIDEA 进行数据采集 我们今天用一个…

TCP/IP 网络模型详解(二)之输入网址到网页显示的过程

当键入网址后&#xff0c;到网页显示&#xff0c;其间主要发生了以下几个步骤&#xff1a; 一、解析URL 下图是URL各个元素所表示的意义&#xff1a; 右边蓝色部分&#xff08;文件的路径名&#xff09;可以省略。当没有该数据时&#xff0c;代表访问根目录下事先设置的默认文…

零基础STM32单片机编程入门(二十四) 内部FLASH详解及读写实战含源码

文章目录 一.概要二.内部FLASH地址空间排布三.内部FLASH主要特色四.内部FLASH读写操作1.FLASH数据读取2.FLASH数据擦除3.FLASH数据写入 五.内部FLASH的各种保护1.写保护2.读保护 六.FLASH读写例程七.CubeMX工程源代码下载八.小结 一.概要 STM32F103C8T6是一款强大而灵活的微控…

Language——基础

前言 开发语言的本质 不同数据类型之间的值传递 正则表达式 (1) 几乎所有语言都支持正则表达式 (2) ^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$ 数据库 (1) 增删改查 一. Python 二.Java 主语言 1. 文件类型 (1) 源代码文件 java——java程序源代码 …

keepalived介绍以及配置主备库自动切换,一条龙服务

Keepalived是什么? Keepalived是一种用于实现高可用性&#xff08;HA&#xff09;的开源软件&#xff0c;它通过虚拟路由冗余协议&#xff08;VRRP&#xff0c;Virtual Router Redundancy Protocol&#xff09;来实现主备切换&#xff0c;从而提高服务的可用性。 虚拟路由冗…

Matplotlib知识点详解(巨详细!!!)

37.Matplotlib&#xff1a; 配置参数&#xff1a; 如果浏览器不显示图片&#xff0c;加上 %matplotlib inline 让图片可以显示中文 plt.rcParams[font.sans-serif]SimHei 让图片可以显示负号 plt.rcParams[axes.unicode_minus]False 支持svg矢量图 %config Inlineback…

[C++] 深入浅出list容器

文章目录 list介绍list接口的使用构造函数iterator迭代器capacity**element access**modifiers list中的迭代器失效问题常见容器及其迭代器类型特性单向迭代器&#xff08;Forward Iterator&#xff09;双向迭代器&#xff08;Bidirectional Iterator&#xff09;随机访问迭代器…

肆[4],VisionMaster全局触发测试说明

1&#xff0c;环境 VisionMaster4.3 2&#xff0c;实现功能 2.1&#xff0c;全局触发进行流程控制执行。 2.2&#xff0c;取像完成&#xff0c;立即运动到下一个位置&#xff0c;同步进行图片处理。 2.3&#xff0c;发送结果的同时&#xff0c;还需要显示图像处理的痕迹。 …

力扣爆刷第168天之TOP200五连刷106-110(每日温度单调栈、盛水最多滑动窗口、全排列回溯)

力扣爆刷第168天之TOP200五连刷106-110&#xff08;每日温度单调栈、盛水最多滑动窗口、全排列回溯&#xff09; 文章目录 力扣爆刷第168天之TOP200五连刷106-110&#xff08;每日温度单调栈、盛水最多滑动窗口、全排列回溯&#xff09;一、138. 随机链表的复制二、739. 每日温…

⌈ 传知代码 ⌋ 记忆注意力用于多模态情感计算!

&#x1f49b;前情提要&#x1f49b; 本文是传知代码平台中的相关前沿知识与技术的分享~ 接下来我们即将进入一个全新的空间&#xff0c;对技术有一个全新的视角~ 本文所涉及所有资源均在传知代码平台可获取 以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦&#x…

【TS】TypeScript数组类型:掌握数据集合的类型安全

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 TypeScript数组类型&#xff1a;掌握数据集合的类型安全引言1. TypeScript数组类…

Three.js结合物理引擎实现掉落效果

<template> </template><script setup> import * as THREE from three import gsap from gsap //导入轨道控制器 import { OrbitControls } from three/examples/jsm/controls/OrbitControls // 导入 dat.gui import { GUI } from three/addons/libs/lil-gui…

好用的抠图软件在哪里找?这篇文章就有几款好用的抠图工具

在图像处理的世界中&#xff0c;抠图技术无疑是一项至关重要的技能。 无论是设计师、摄影师还是普通的图像编辑爱好者&#xff0c;都可能需要从一张图片中精确地分离出某个对象或元素。但是&#xff0c;手动抠图不仅耗时而且技术要求高&#xff0c;这时候&#xff0c;一款优秀…

PTrade常见问题系列17

是否支持量化帐号的指定服务器分发? 是否可以支持部分量化帐号不根据原有分发规则&#xff0c;而是直接指定分发&#xff1f; 1、若需要增加VIP服务器专用于新增的帐号进行分配&#xff0c;可以参考【量化】量化Nginx用户指定服务器处理步骤.docx&#xff1b; 2、若所有服务…

【音视频之SDL2】Windows配置SDL2项目模板

文章目录 前言 SDL2 简介核心功能 Windows配置SDL2项目模板下载SDL2编译好的文件VS配置SDL2 测试代码效果展示 总结 前言 在开发跨平台的音视频应用程序时&#xff0c;SDL2&#xff08;Simple DirectMedia Layer 2&#xff09;是一个备受欢迎的选择。SDL2 是一个开源库&#x…

“AI+”时代,人工智能前景怎么样?

随着“互联网”到“AI”的转型&#xff0c;时代发展迎来了新的阶段。 在政策、技术和市场的三重驱动之下&#xff0c;人工智能正在快速响应各领域的广泛诉求。虽然人工智能的兴起“打消”了一些传统领域的念想&#xff0c;但同时也开辟了更加多元化的市场。 当下互联网大厂人…