Java【String】【StringBuilder】【StringBuffer】你都会用吗

news2024/12/23 16:00:14

文章目录

  • 前言
  • 一、常用的方法
    • 1、字符串构造
    • 2、字符串比较
    • 3、字符串查找
    • 4、字符串转化
    • 5、字符串替换
    • 6、字符串分割
    • 7、字符串截取
  • 二、字符串的不可变性
  • 三、StringBuilder、StringBuffer
  • 总结


前言

在校招和笔试过程中,字符串是相当频繁被问到的话题,在之前的文章【数据类型与变量】中提到了,Java中设计了一种引用数据类型:String,可以专门来存储字符串。

今天主要介绍不可变的String,以及可变的StringBuilder和StringBuffer


提示:是正在努力进步的小菜鸟一只,如有大佬发现文章欠佳之处欢迎评论区指点~ 废话不多说,直接上干货!

一、常用的方法

1、字符串构造

我们常用的定义一个字符串的方式为:

        String str = "我爱你中国";

我们知道,String是一个引用数据类型,是一个类,类可以new对象,所以还可以这样定义一个字符串:

        String str = new String("我爱你中国");

实际上,正因为String是一个类,所以这样的写法才标准,只不过编译器提供了一种简化的写法,就是直接赋值

要学习String这个类,首先要从这个类的构造方法学起

在IDEA中——敲两次shift——导航栏搜索String——选择class——选择String java.lang
就可以看到String这个类中所有的成员属性和方法了

例如:
在这里插入图片描述
这只是一部分,也是最常用的三种定义字符串的方式,代码如下:

        // 1
        String str1 = new String();
        str1 = "我爱你中国";
        // 2
        String str2 = new String("我爱你中国");
        // 3
        char[] value = {'我','爱','你','中','国'};
        String str3 = new String(value);

简单了解了String类的构造方法之后,需要注意的是:
String 内部并不存储字符串本身

我们打开调试窗口:
在这里插入图片描述
可以看到,String类new出来的三个对象中的成员变量都只有两个:value( 数组类型 ) 和 hash
hash有什么作用咱先别管 ,只需看到value这个数组,可以推断,实际上 字符串是被存放在了一个数组中,而数组也是一个引用类型,可以理解为value的值就是数组的地址

例如 str1 这个字符串,可以简单理解为:
在这里插入图片描述


2、字符串比较

一般有两种场景:1,字符串是否相同 2,大小是否相等

1,判断字符串是否相同:

        String str1 = new String("我爱你中国");
        String str2 = new String("我爱你中国");
        
        System.out.println(str1 == str2);
        // 输出:false
        System.out.println(str1.equals(str2));
        // 输出:true

因为 str1 和 str2 存储的都是对象的地址,两个对象的地址不同
equals 是用来比较两个引用指向的对象的内容是否一致

2,比较字符串大小关系

        String str1 = new String("我爱你中国");
        String str2 = new String("我爱你中国");
        String str3 = new String("我爱你中国我爱你中国");

        System.out.println(str1.compareTo(str2));
        // 输出:0
        System.out.println(str2.compareTo(str3));
        // 输出:-5

compareTo 是用来比较两个引用指向的对象的内容大小关系
比较方式:
先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值

        String str1 = new String("iloveyou");
        String str2 = new String("ILOVEYOU");

        System.out.println(str1.compareTo(str2));
        // 输出:32
        System.out.println(str1.compareToIgnoreCase(str2));
        // 输出:0

compareToIgnoreCasecompareTo方式相同,但是忽略大小写比较


3、字符串查找

方法功能
char charAt (int index)返回 index 位置上字符,如果 index 为负数或者越界,抛出 IndexOutOfBoundsException 异常
int indexOf (int ch)返回 ch 第一次出现的位置,没有返回-1
int indexOf (int ch, intfromIndex)从 fromIndex 位置开始找 ch 第一次出现的位置,没有返回-1
int indexOf (String str)返回 str 第一次出现的位置,没有返回-1
int indexOf (String str, intfromIndex)从 fromIndex 位置开始找str第一次出现的位置,没有返回-1
int lastIndexOf (int ch)从后往前找,返回 ch 第一次出现的位置,没有返回-1
int lastIndexOf (int ch, intfromIndex)从 fromIndex 位置开始找,从后往前找 ch 第一次出现的位置,没有返回-1
int lastIndexOf (String str)从后往前找,返回 str 第一次出现的位置,没有返回-1
int lastIndexOf (String str, intfromIndex)从 fromIndex 位置开始找,从后往前找 str 第一次出现的位置,没有返回-1

1,char charAt (int index)

        String str = "我爱你中国";
        System.out.println(str.charAt(0));
        // 输出第一个字符:我
        System.out.println(str.charAt(10));
        // 找不到第10个字符,抛出 IndexOutOfBoundsException 异常 

因为字符串存放在数组中,所以编号和数组下标一致,从0开始

2, int indexOf(int ch)

        String str = "ababcabcdabcde";
        System.out.println(str.indexOf('c'));
        // 找到 str 这个字符串中第一次出现 c 的位置,在4下标处
        // 输出:4

3,int indexOf (int ch, intfromIndex)
多了一个参数,表示起始位置的下标,如果不写第二个参数,默认从0下标处开始找

        String str = "ababcabcdabcde";
        System.out.println(str.indexOf('c',4));
        // 从4位置开始找   输出:4
        System.out.println(str.indexOf('c',5));
        // 从5位置开始找   输出:7

4,int indexOf (String str)

        String str = "ababcabcdabcde";
        System.out.println(str.indexOf("abc"));
        // 找字符串 "abc" 在 str 中出现的位置
        // 输出:2

实现这个方法,有一种比较有难度的算法:KMP算法,感兴趣的小伙伴可以看看我写的这篇文章:大白话式解析KMP算法

5,int indexOf (String str, intfromIndex)
多了一个参数,表示起始位置的下标,如果不写第二个参数,默认从0下标处开始找

        String str = "ababcabcdabcde";
        System.out.println(str.indexOf("abc"));
        System.out.println(str.indexOf("abc",3));
        // 从3位置开始找 "abc"   输出:5

6,int lastIndexOf (int ch)
方法名多了一个单词:last
这个方法表示从后往前找

        String str = "ababcabcdabcde";
        System.out.println(str.lastIndexOf('a'));
        // 从后往前找到第一次出现字符'a',返回'a'的下标
        // 输出:9

7,int lastIndexOf (int ch, intfromIndex)

        String str = "ababcabcdabcde";
        System.out.println(str.lastIndexOf('a',8));
        // 从8位置处开始从后往前找,相当于把8位置当成最后一位
        // 输出:5

剩下的就不再赘述啦,原理同上


4、字符串转化

1,将数字转字符串:

        String str = String.valueOf(123);
        System.out.println(str);

valueOf能转化的类型有很多:
在这里插入图片描述
这就是重载的好处,不需要设计那么多方法名

2、字符串转数字:

        String str = "123";
        int a = Integer.parseInt(str);
        System.out.println(a);

3,大小写转化:

        String str1 = "love";
        String str2 = "LOVE";
        System.out.println(str1.toUpperCase());
        // 输出:LOVE
        System.out.println(str2.toLowerCase());
        // 输出:love

4,字符串转数组

        String str = "我爱你中国";
        char[] array = str.toCharArray();

5,数组转字符串

        char[] array = {'我','爱','你','中','国'};
        String str = new String(array);

5、字符串替换

        String str = "abababaabab";
        String newStr1 = str.replaceAll('a','b');
        // 将字符 'a' 全部替换为 'b'
        String newStr1 = str.replaceFirst('a','b');
        // 将首个字符 'a' 替换为 'b'
        System.out.println(newStr);
        // 输出:bbababaabab

6、字符串分割

将一个完整的字符串按照指定的分隔符划分为若干个子字符串

1,String[] split (String regex) 将字符串全部拆分

        String str = "I LOVE YOU";
        String[] strs = str.split(" ");
        // 按照空格分割 返回值类型为字符型数组
        for (String newstr : strs) {
        // 遍历数组
            System.out.println(newstr);
        }
// 输出:
// I
// LOVE
// YOU

2,String[] split (String regex, int limit) 将字符串以指定的格式,拆分为 limit

        String str = "I LOVE YOU";
        String[] strs = str.split(" "2);
        // 多了一个参数,表示分割成两组
        for (String newstr : strs) {
        // 遍历数组
            System.out.println(newstr);
        }
// 输出:
// I
// LOVE YOU

注意:
字符" | ", " + ", " . ", " * " 都得加上转义字符,前面加上 " \ "
而如果是 " \ " ,那么就得写成 " \\ "
如果一个字符串中有多个分隔符,可以用 " | " 作为连字符,例如:

        String str = "I-LOVE=YOU";
        String[] strs = str.split("-|=");
        for (String newstr : strs) {
            System.out.println(newstr);
        }
// 输出:
// I
// LOVE
// YOU

7、字符串截取

从一个完整的字符串之中截取出部分内容

1,String substring (int beginIndex) 从指定索引截取到结尾

        String str = "我爱你中国";
        String newstr = str.substring(2);
        // 从2下标位置开始,截取之后的所有字符
        System.out.println(newstr);
        // 输出:你中国

2,String substring (int beginIndex, int endIndex) 截取部分内容

        String str = "我爱你中国";
        String newstr = str.substring(2,3);
        // 从2下标位置开始,截取到3下标位置(不包含3下标)
        System.out.println(newstr);
        // 输出:你

二、字符串的不可变性

为什么说字符串是不可变的呢?

说到字符串的不可变性就要提出“ 常量池 ” 的概念了,这里暂不讲解,随着学习的深入,之后再做分享,现在先简单分析一下:

在这里插入图片描述
可以看到第114行 value 这个数组是被 private final 修饰的,那不可变性是因为 private 还是因为 final 呢?

关于 final:
final 修饰类表明该类不想被继承,final 修饰 引用类型 表明该引用变量不能引用其他对象,但是其引用对象中的内容是可以修改的

        final int[] array = {1,2,3,4,5};
        array[0] = 10;
        System.out.println(array[0]);
        // 可以改变array指向的对象的值

        array = new int[]{1,2,3,4,5};
        // 报错,不能再改变array的指向

真正使字符串不可变的是因为 private ,把 value 封装起来了,使得value只能在String这个类里面访问,并且String类中没有提供 setter 和 getter 方法,所以不能在String类外范围value

了解即可:
为什么 String 要设计成不可变的?(不可变对象的好处是什么?)
方便实现字符串对象池,如果 String 可变,那么对象池就需要考虑写时拷贝的问题了
不可变对象是线程安全的
不可变对象更方便缓存 hash code,作为 key 时可以更高效的保存到 HashMap 中


三、StringBuilder、StringBuffer

在了解 StringBuilder 和 StringBuffer 之前呢,我们先了解一下字符串拼接

Java提供了使用加号(+)拼接字符串的功能,例如:

public class Test {
    public static void main(String[] args) {
        String str = "我爱你";
        str += "中国";
        System.out.println(str);// 输出:我爱你中国
    }
}

但刚刚说过,字符串是不可修改的,所以这种方式的拼接,并不是对str本身进行修改,而是又 new 了不止一个临时对象,所以这种方式的对字符串的拼接,效率十分低下

如何去证明?打开汇编界面可以证明,博主才疏学浅,就不过多展示了,感兴趣的可以自己去查一下,这里只说结论:

    	str += "中国";

这一行代码,实际上是这四行:

        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(str);
        stringBuilder.append("中国");
        str = stringBuilder.toString();

我们知道,双引号括起来的就是一个字符串对象,并且我们摁住 ctrl 点击 toString 方法,就可以看到 toString 方法的返回值处,也 new 了一个对象
在这里插入图片描述
再加上 new 出来的 stringBuilder 对象,可以算出,在 “拼接” 这看似一行代码背后

    	str += "中国";

实际上创建了三个临时对象


所以,如果实在循环当中使用加号对字符串进行拼接,效率可不是一般的低呀,接下来我们就要认识一下 StringBuilder 和 StringBuffer

StringBuilder 和 StringBuffer 对比 String 最直接的区别就是,StringBuilder 和 StringBuffer new出来的字符串是可变的

通过 StringBuilder 的 reverse(逆序)方法就可以证明 StringBuilder 的字符串可变性:

public class Test {
    public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("我爱你");
        stringBuilder.reverse();
        System.out.println(stringBuilder);// 输出:你爱我
    }
}

这里我们并没有重新重新定义字符串类型的变量,但打印 stringBuilder 的时候却变成了逆序之后的“你爱我”,说明这个字符串本身确实是被修改了

我们还可以通过StringBuilder 的 append(附加)方法再证明一下:

public class Test {
    public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("我爱你");
//        stringBuilder.reverse();
        stringBuilder.append("中国").append("母亲");
        System.out.println(stringBuilder);// 输出:我爱你中国母亲
    }

这里可以看到,append() 方法甚至可以连续使用

这两个栗子就充分说明了,StringBuilder 实例化出来的对象,调用方法的返回值都是字符串本身(this),所以不会产生临时对象
StringBuffer 同理

Java 中提供的 StringBuilder 和 StringBuffer 这两个类大部分功能是相同的,这两个类有自己的一些方法是 String 类没有的(互补关系),具体在这里不多赘述了,感兴趣的可以自己查一下在线文档

那么这两个类又有什么不同呢?
功能基本都一样,刚刚用 StringBuilder 的代码 StringBuffer 也可以,他俩的区别就是就在于:
说人话:在多线程时,StringBuffer 内置有 “一把锁” ,会相对安全

但是!也不能无脑使用 StringBuffer ,频繁的 “上锁”,“开锁” 的过程也会消耗系统资源的呀,等学习到多线程的时候再做分享~


总结

以上就是今天要讲的关于【String类】的内容,还涉及到了【StringBuilder】【StringBuffer】,主要介绍了 String 类的一些方法,还希望看过本篇的小伙伴们自己练习一下噢

如果本篇对你有帮助,请点赞收藏支持一下,小手一抖就是对作者莫大的鼓励啦🤪🤪🤪


上山总比下山辛苦
下篇文章见

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

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

相关文章

iMazing兼容Win和Mac2023免费版iOS设备管理器

iMazing是一款ios设备管理软件,该软件支持对基于iOS系统的设备进行数据传输与备份,用户可以将包括:照片、音乐、铃声、视频、电子书及通讯录等在内的众多信息在Windows/Mac电脑中传输/备份/管理。 软件备份是指将一部手机上的重要信息和资料&…

Pytorch -> ONNX -> TensorRT 模型转换与部署

系统环境: Ubuntu 18.04Cuda 11.3Cudnn 8.4.1 1 、Pytorch -> ONNX 网上相关流程很多,我就不重复了 可以参考Pytorch分类模型转onnx以及onnx模型推理 或者直接看Pytorch官方怎么干的。 ONNX Github onnxruntime调用onnx模型推理时有一个provider…

HTML5期末大作业:基于HTML+CSS+JavaScript茶文化中国水墨风格绿色茶叶销售(5页) 学生网页设计作业源码

🎉精彩专栏推荐 💭文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业: 【📚毕设项目精品实战案例 (10…

用coding向你最爱的人说圣诞快乐

🎄🎄🎄圣诞节即将到来,今天让我们用编码的方式向你最爱的人表达圣诞节快乐。 圣诞节的起源 圣诞节源自古罗马人迎接新年的农神节,与基督教本无关系。在基督教盛行罗马帝国后,教廷将这种民俗节日纳入基督教体…

DenseNet的基本思想

之前的文章介绍过残差网络的基本思想:残差网络的思想就是将网络学习的映射从X到Y转为学习从X到Y-X的差,然后把学习到的残差信息加到原来的输出上即可。即便在某些极端情况下,这个残差为0,那么网络就是一个X到Y的恒等映射。其示意图…

Java基础类型和运算符

文章目录变量与常量变量的命名规则常量final 关键字修饰的常量字面常量基本类型整型基本整型变量 int长整型 long短整型 short比特型 byte浮点数 float和double关于3*0.10.3三种特殊的double字符型 char布尔类型 boolean类型转换隐式类型提升强制类型转换运算符算数运算符基本四…

vue中打印插件vue-print-nb(二)-实例之两种方法——安包之设置一个id和绑定一个对象 下载print.js之ref设置锚点

vue中打印插件vue-print-nb(二)-实例之两种方法——安包之设置一个id和绑定一个对象 & 下载print.js之ref设置锚点 第一种方法 方式1、设置一个id ① 给要打印的部分设置一个 id ② 在打印按钮中添加 v-print"#id名" 1、安装vue-print-nb插件 npm install v…

Firefly RK3399 PC pro Android 10下载验证

一.Android 源码以及image 1.Android 10代码链接: 百度网盘 请输入提取码 密码:1234 下载后检查md5值,检查下载是否正确: fb41fcdc48b1cf90ecac4a5bb8fafc7a Firefly-RK3399_Android10.0_git_20211222.7z.001 82d665fb54fb412…

Flutter ー Authentication 认证

Flutter ー Authentication 认证 原文 https://medium.com/simbu/flutter-authentication-adb8df7cf673 前言 如果我相信我知道你是谁那我就能让你查看你的个人 应用 application 资料。 身份验证可能是应用程序必须处理的最大的交叉问题。 将它作为一个特性添加到 DigestableP…

HashMap JDK1.7与1.8的区别

结构 首先HashMap在1.7中是以数组链表的形式存在的, 而HashMap在1.8中则是以数组链表红黑树构成的, 当一个节点的链表长度超过8并且数组长度超过64时会将链表转换为红黑树, 初始化 初始容量大小介绍 说到数组就不得不提HashMap里面的成员变量DEFAULT_INITIAL_CAPACITY也就是…

Mysql进阶学习(八)DDL语言+数据类型和DTL语言

Mysql进阶学习(八)DDL语言与DTL语言DDL语言1、简介:1.1、库的管理1.1.1、库的创建1.1.2、库的修改1.1.3、库的删除1.2、表的管理1.2.1.表的创建 ★1.2.2.表的修改1.2.3.表的删除1.2.4.表的复制测试案例1. 创建表dept12. 将表departments中的数…

SpringBoot_整合Thymeleaff模板引擎

Thymeleaf模板引擎的主要目标是将优雅的自然模板带到开发工作流程中,并将HTML在浏览器中正确显示,并且可以作为静态原型,让开发团队能更容易地协作。Thymeleaf能够处理HTML,XML,JavaScript,CSS甚至纯文本。…

Qt扫盲-Qt Designer 设计师使用总结

Designer 设计师使用总结一、顶部菜单栏1. 常用的菜单内容2. 快捷工具栏说明二、左侧控件栏1. 组件分类2. 筛选三、中间绘图区1. 左侧控件区拖放控件到中间2. 中间区域布局3. 属性修改四、右侧属性栏1. 对象查看器2. 属性编辑器3.组织结构2. 属性设置五、美化专栏1.单个设置层叠…

微服务框架 SpringCloud微服务架构 12 DockerCompose 12.2 部署微服务集群

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式,系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构12 DockerCompose12.2 部署微服务集群12.2.1 直接开干12 DockerCompose 1…

大数据:Hive简介及核心概念

一、简介 Hive 是一个构建在 Hadoop 之上的数据仓库,它可以将结构化的数据文件映射成表,并提供类 SQL 查询功能,用于查询的 SQL 语句会被转化为 MapReduce 作业,然后提交到 Hadoop 上运行。 特点: 简单、容易上手 (…

做短视频不知道靠什么变现,分享三个自我商业定位的方法,适用普通人

如果说你还停留在我也不知道我可以靠什么赚钱这样的一个状态当中。那我给你三个自我商业定位的方法。篇幅较长,点赞收藏慢慢看哦 首先第一个方法,从工作上或者专业的事情上找变现的方法。 那么你们需要了解一个概念叫做知识的诅咒。什么意思呢&#xf…

【论文整理1】On the Continuity of Rotation Representations in Neural Networks

1.前置知识 1.1 Gram-Schmidt正交化 【参考阅读】Gram-Schmidt过程 看完这篇应该基本能理解,但是他对于公式的讲解有一个地方讲解得不是很清楚! 即为什么分母是平方形式呢? 1.2 差集 定义:差集是一种集合运算,记A&#xff0…

Java并发编程—CompletableFuture的介绍和使用

在博主上一篇博客介绍中,Java并发编程—java异步Future的迭代过程_小魏快起床的博客-CSDN博客,这里面给大家分析了Future的使用过程和一些存在的问题,那么针对里面出现的阻塞问题,博主将在这一篇文章给大家介绍清楚 &#x1f34f…

MyBatis框架简介

MyBatis是一个开源的数据持久层框架,内部封装了通过JDBC访问数据库的操作,支持普通的SQL查询、存储过程和高级映射。作为持久层框架,主要思想是将程序中的大量的SQL语句分离出来,配置在相应的配置文件中,这样可以在不修…

Java—数据类型

文章目录数据类型八大基本数据类型Java中有了基本数据类型,为什么还要包装类型String字符串类型函数字符串类的length()方式是否能够得到字符串内有多少个字符?不可变字符串String为什么要设计成不可变的?boolean类型占多少位?为什…