java基础之 String\StringBuffer\ StringBuilder

文章目录

  • String
    • 字符串的创建
    • 为什么说String是不可变的?
    • 创建后的字符串存储在哪里?
    • 字符串的拼接
    • String类的常用方法
  • StringBuilder & StringBuffer
    • 使用方法
    • 验证StringBuffer和StringBuilder的线程安全问题
  • 总结
    • 三者区别
    • 什么情况下用+运算符进行字符串连接比调用StringBuffer/StringBuilder 对象的 append 方法连接字符串性能更好?

String

String不是基本数据类型,是引用类型。

字符串的创建

  • 方法一:直接赋值
    String s01 = "helloWorld";
    
  • 方法二:通过new对象创建
    String s02 = new String("helloWorld");
    
  • 方法三:拼接创建
    String s03 = "hello"+"World";
    
  • 方法四:通过数组创建
    byte[] arr = {10,20,30,40};
    String s04 = newString(arr);
    

为什么说String是不可变的?

  • String类型是不可变的

    其类是由final修饰的,这就导致了在修改字符串内容是会创建新的String对象,会增加内存的使用和开销。
    (下方为源码截图)

    在这里插入图片描述

    如果需要修改字符串而不产生新的对象,我们可以使用StringBuffer 或者StringBuilder

  • String类型是线程安全的

    因为String是不可变的,意味着一旦创建了String对象,字符串的内容就不能被更改。任何对字符串的修改都会生成一个新的String对象

  • 为什么需要设置成不可变的?

    因为java设计者认为字符串使用是比较频繁的,设置为不可变的可以允许多个客户端同时共享这一字符串,从而保证了线程安全。

创建后的字符串存储在哪里?

  • 字符串创建后存在于运行时常量池中。
    (在jdk1.7以前,运行时常量池存在于方法区中。从jdk1.7开始,就存在于堆中。)

  • 当创建一个字符串对象时,如果字符串内容在常量池中已经存在,JVM会返回常量池中的引用;如果不存在,JVM会在常量池中创建一个新的字符串对象‌

字符串的拼接

  • 我们先看一下代码

    String s01 = "aaa";
    String s02 = "bbb";String ss01 = "aaabbb";
    String ss02 = s01+s02;
    System.out.println(ss01==ss02);  // (1)结果分析看下方String ss03 = ss02.intern();
    System.out.println(ss01==ss03); // (2)结果分析看下方String ss04 = "aaa"+"bbb";
    System.out.println(ss01==ss04); // (3)结果分析看下方String ss05 = s01.concat(s02);
    System.out.println(ss01==ss05); // (4)结果分析看下方
    
  • (1)运行结果为:false

    ① s01和s02为字符串变量
    ② 字符串变量拼接是会现在在堆中new一个对象,并将地址赋值给ss02,然后再让ss02指向常量池。
    ③ 因为无论连接后的数据是否在常量池,ss02执行的都是堆空间中的地址,故为false

  • (2)运行结果为:true

    String.intern()用于优化字符串的内存使用,可以减少内存消耗。它可以确保相同内容的字符串只存储一次。
    即,intern()方法的作用是把字符串加入到常量池中,然后返回这个字符串在常量池中的地址。

  • (3)运行结果为:true

    ① 字符串相加时,都是静态字符串,相加的结果会添加到常量池中。
    ② 如果常量池中有则返回其引用;如果没有则创建该字符串再返回其引用。
    ③ “aaabbb”在创建ss01时就已经存在常量池中了,所以ss04在创建的时候会发现已经存在"aaabbb"了,返回的是同一个引用,即ss01和ss04都是"aaabbb"在常量池中的引用,故是相等的。

  • (4)运行结果为:false

    追加的字符串如果不是空,则会产生一个新的对象。
    下方为concat方法的源码。即如果追加的字符串是空,返回当前对象,如果不是空,则会创建一个新的对象,而新对象是在堆中创建的,故ss05的地址是在堆中

    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);}
    

String类的常用方法

String str = "Hello,who are you?";
// (一) 返回指定索引处的char值
char c = str.charAt(10); // 打印结果为:H。如果超出范围则会报错
// (二)将指定字符串连接到此字符串的结尾
String newStr = str.concat("Joy");  // 打印结果为:Hello,who are you?Joy
// (三)测试字符串是否已指定的后缀结束
Boolean flag = str.endsWith("hello"); // 打印结果为:false
// (四)将string编码为byte序列,并将结果存储到一个新的byte数组中
byte[] bytes = str.getBytes(); // bytes = {72,101,108,108,111,44,119,104,111,32,97,114,101,32,121,111,117,63};
// (五)返回指定字符在该字符串中第一次出现的索引  或指定字符串第一次出现的索引
int index = str.indexOf(101);   // 101是e的字符值,其所在的索引位置是 1
int index01 = str.indexOf("you");   // 14
// (六)返回字符串的长度
int len = str.length();  // 18
// (七)替换字符串中的内容,第一个参数为被替换的内容,后一个参数为替换的新内容
String str01 = str.replace("who","where");   // str01打印结果:Hello,where are you?
// (八)拆分字符串
String[] strings = str.split("");  // String[] strings = {H,e,l,l,o,,,w,h,o, ,a,r,e, ,y,o,u,?};
String[] strings1 = str.split(" "); // String[] strings1 = {Hello,who,are,you?};
String[] strings2 = str.split(","); // String[] strings2 = {Hello,who are you?};
// (九)将字符串转换为一个新的字符数组
char[] chars = str.toCharArray(); // char[] chars = {H,e,l,l,o,,,w,h,o, ,a,r,e, ,y,o,u,?};
// (十)忽略字符串的前后空白
String str2 = " hello world  ";
String str3 = str2.trim();   // String str3 = "hello world";
// (十一)大小写转换
String str02 = str.toLowerCase();  // str02 = hello,who are you?
String str03 = str.toUpperCase();   // str03 = HELLO,WHO ARE YOU?
// (十二)判断是否包含指定的字符串序列
Boolean flag1 = str.contains("who");  // flag1 = true;
// (十三)判断字符串是否为空
Boolean flag2 = str.isEmpty();  // flag2 = false;

StringBuilder & StringBuffer

  • 针对于String的不可变性,StringBuilder和StringBuffer是可变的,其内容可以随意修改
  • StringBuilder和StringBuffer的对象被多次修改后,不陈胜新的未使用对象,即每次都会对对象本身进行操作,故对字符串进行修改推荐使用

使用方法

  • StringBuilder和StringBuffer使用的功能是一样的,这里就一起来整理,不分开了

  • 其他功能同String,再次也就不一一列举了

       StringBuilder builder = new StringBuilder("hello");StringBuffer buffer = new StringBuffer("hello");// 追加内容不能为空,可以追加其他基本类型的内容。注意添加后的内容是紧紧挨着的,没有空格的builder.append(3411);   buffer.append(3411);builder.append("world,hello");    // 打印结果:helloworldbuffer.append("world,hello");// 在索引2处添加"java",打印结果:hejavalloworldbuilder.insert(2,"java");  buffer.insert(2,"java");// 删除索引2到索引6之间的内容,左闭右开;打印结果:helloworldbuilder.delete(2,6);    buffer.delete(2,6);// 反转字符串builder.reverse();  buffer.reverse();// 两者扩容机制是一样的。初始容量为 16+字符串长度。扩容计算公式为:(capacity+1)*2int builderCapacity = builder.capacity();  // 打印结果:21。int bufferCapacity = buffer.capacity();int builderLen = builder.length();  // 打印结果:15int bufferLen = buffer.length();
    

验证StringBuffer和StringBuilder的线程安全问题

StringBuilder builder = new StringBuilder();
StringBuffer buffer = new StringBuffer();
Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {for(int i=0;i<1000000;i++){builder.append("b");buffer.append("b");}}
});
t1.start();
Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {for(int i=0;i<1000000;i++){builder.append("a");buffer.append("a");}}
});
t2.start();try {t1.join();t2.join();
} catch (InterruptedException e) {e.printStackTrace();
}finally {System.out.println(builder.length());System.out.println(buffer.length());
}

打印结果是buffer的永远是2000000,但是builder的会一直变化
(自己可以拷贝代码试试看哦)

总结

三者区别

  • 可变性 or 不可变性

    String是不可变的,是只读字符串。
    StringBuffer和StringBuilder是可变的。

  • 安全性

    StringBuffer是线程安全的;
    StringBilder是线程不安全的.
    因为StringBuilder没有被synchronize修饰,属于单线程下的,减少了线程切换的开销,所以其效率要比StringBuffer效率高

  • 性能及使用场景

    ‌String每次操作都会生成新的对象,性能较低,尤其是在频繁修改字符串的场景下;
    StringBuilder‌在单线程环境中,没有同步机制,性能较高。适合在单线程环境中频繁修改字符串的场景‌;
    ‌StringBuffer‌在单线程环境中,由于所有方法都是同步的,性能较低。但在多线程环境中,它可以安全地被多个线程使用‌

什么情况下用+运算符进行字符串连接比调用StringBuffer/StringBuilder 对象的 append 方法连接字符串性能更好?

  • 如果使用少量的字符串操作,使用 (+运算符)连接字符串;
  • 如果频繁的对大量字符串进行操作,则使用
    • 1:全局变量或者需要多线程支持则使用StringBuffer;
    • 2:局部变量或者单线程不涉及线程安全则使有StringBuilder。

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

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

相关文章

深度解析阿里的Sentinel

1、前言 这是《Spring Cloud 进阶》专栏的第五篇文章&#xff0c;这篇文章介绍一下阿里开源的流量防卫兵Sentinel&#xff0c;一款非常优秀的开源项目&#xff0c;经过近10年的双十一的考验&#xff0c;非常成熟的一款产品。 文章目录如下&#xff1a; 2、什么是sentinel&…

移远通信推出全星系多频段高精度定位定向GNSS模组LG580P,引领高精度导航新时代

近日&#xff0c;全球领先的物联网整体解决方案供应商移远通信宣布&#xff0c;正式发布其全星系多频段高精度GNSS模组LG580P。该模组具备高精度、高稳定性、低功耗等特点&#xff0c;并支持20Hz RTK Heading 更新频率&#xff0c;为智能机器人、精准农业、测量测绘、自动驾驶…

Python设计模式探究:单例模式实现及应用解析

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storm…

企业微信会话存档引用com.tencent.wework.Finance出错?

报错&#xff1a; 会话存档引用com.tencent.wework.Finance出错&#xff0c;找不到该类&#xff0c;报错如下&#xff1a;java.lang.NoClassDefFoundError: Could not initialize class com.tencent.wework.Finance 这个问题怎么解决&#xff1f; 解决方案&#xff1a;需要下载…

【前端基础】盒子模型

目标&#xff1a;掌握盒子模型组成部分&#xff0c;使用盒子模型布局网页区域 01-选择器 结构伪类选择器 基本使用 作用&#xff1a;根据元素的结构关系查找元素。 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8">…

鸿蒙开发:ArkUI Toggle 组件

ArkUI提供了一套完整的UI开发工具集&#xff0c;帮助开发者高效完成页面的开发。它融合了语言、编译器、图形构建等关键的应用UI开发底座&#xff0c;为应用的UI开发提供了完整的基础设施&#xff0c;包括简洁的UI语法、丰富的UI功能以及实时界面预览工具等&#xff0c;可以支持…

【LeetCode每日一题】——802.找到最终的安全状态

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时空频度】九【代码实现】十【提交结果】 一【题目类别】 图 二【题目难度】 中等 三【题目编号】 802.找到最终的安全状态 四【题目描述】 有一个有…

安利一款开源企业级的报表系统SpringReport

SpringReport是一款企业级的报表系统&#xff0c;支持在线设计报表&#xff0c;并绑定动态数据源&#xff0c;无需写代码即可快速生成想要的报表&#xff0c;可以支持excel报表和word报表两种格式&#xff0c;同时还可以支持excel多人协同编辑&#xff0c;后续考虑实现大屏设计…

考公人数攀升?地信、测绘、地质、遥感等专业,能报考哪些单位

近年来&#xff0c;考公人数持续飙升&#xff0c;国考报名人数更逐年攀升。2025年国家公务员考试共有341.6万人通过资格审查&#xff0c;报录比达86:1。国考报名人数再创新高。 国家公务员考试时间安排 地理学相关岗位分析 地信属于地理科学类&#xff0c;测绘类中不包括地信&…

LabVIEW 离心泵机组故障诊断系统

开发了一套基于LabVIEW图形化编程语言设计的离心泵机组故障诊断系统。系统利用先进的数据采集技术和故障诊断方法&#xff0c;通过远程在线监测与分析&#xff0c;有效提升了离心泵的预测性维护能力&#xff0c;保证了石油化工生产的连续性和安全性。 项目背景及意义 离心泵作…

YOLOv10改进策略【卷积层】| CVPR-2023 SCConv 空间和通道重建卷积:即插即用,减少冗余计算并提升特征学习

一、本文介绍 本文记录的是利用ScConv优化YOLOv10的目标检测网络模型。深度神经网络中存在大量冗余&#xff0c;不仅在密集模型参数中&#xff0c;而且在特征图的空间和通道维度中。ScConv模块通过联合减少卷积层中空间和通道的冗余&#xff0c;有效地限制了特征冗余&#xff…

Linux 文件系统权限

文件的一般权限 文件详细信息 使用命令 ll 或 ls -l 查看 文件权限构成 权限针对三类对象定义 owner &#xff1a;所有者&#xff0c;缩写 u group &#xff1a;所属组&#xff0c;缩写 g other &#xff1a;其他人&#xff0c;缩写 o 访问者三种权限 组成模式分析 …

C++上机实验|多态性编程练习

1.实验目的 (1)理解多态性的概念。 (2)掌握如何用虚函数实现动态联编 (3)掌握如何利用虚基类。 2.实验内容 设计一个飞机类 plane,由它派生出歼击机类fighter和轰炸机类 bomber,歼击机类fighter 和轰炸机类bomber 又共同派生出歼轰机(多用途战斗机)。利用虚函数和虚基类描述…

学习threejs,使用对象组合

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.Object3D 三维物体 二…

遇到的问题

刚遇到的问题&#xff1a; 一直以为这个图片数据结构是以下这种&#xff1a; {"descrlong1": [{"CL04": "人力违纪"},{"CL05": "其他"}], }其实数据结构是&#xff1a; {"descrlong1": [{"key": &quo…

发现8个高风险漏洞 NVIDIA GeForce用户必须更新GPU驱动程序

所有NVIDIA GeForce图形处理器都面临着高风险&#xff0c;因为该公司在其图形处理器驱动程序中发现了几个漏洞&#xff0c;这些漏洞可能会让黑客利用你的系统。公司敦促用户更新到最新的GeForce显示屏和VGPU驱动程序&#xff0c;以确保他们的系统不受任何漏洞的影响。 NVIDIA在…

Redis 中 Bitmap 原理和应用

Bitmap Redis中的Bitmap&#xff08;位图&#xff09;是一种较为特殊数据类型&#xff0c;它以最小单位bit来存储数据&#xff0c;我们知道一个字节由 8个 bit 组成&#xff0c;和传统数据结构用字节存储相比&#xff0c;这使得它在处理大量二值状态&#xff08;true、false 或…

微信小程序开发,诗词鉴赏app

文章目录 1. 项目功能思维导图2. 项目涉及到的技术点3. 开发环境4. 项目运行效果5. 部分功能实现6. 关于本人其它项目的介绍 1. 项目功能思维导图 2. 项目涉及到的技术点 使用MySQL数据库实现数据存储使用setInterval实现启动页3s倒计时使用storage实现数据持久化存储&#xf…

什么是阿里云上的主机安全服务?

在数字化时代&#xff0c;数据安全和网络安全成为了企业最关心的问题之一。随着越来越多的企业将业务迁移至云端&#xff0c;如何确保云环境的安全性&#xff0c;成为了企业必须面对的重要挑战。阿里云安全中心&#xff08;SAS&#xff09;作为一款全面的云安全解决方案&#x…

在K8s平台部署个人博客

在K8s平台部署个人博客 实验步骤查看wordpress前端的service配置word press 实验步骤 kubectl create secret generic mysql-pass --from-literalpasswordYOUR_PASSWORD把mysql.tar.gz和wordpress.tar.gz上传到K8s工作节点&#xff0c;手动解压即可&#xff1a; 通过网盘分享的…