当前位置: 首页 > article >正文

java中的String类、StringBuffer类、StringBuilder类的详细讲解(包含相互之间的比较)

文章目录

  • 一、String 类
    • 1 String 类的介绍
    • 2 String 对象创建的两种方式
    • 3 测试题加深理解
      • (1) 例题一
      • (2)例题二
      • (3) 例题三
    • 4 String 类的常用方法
      • (1)`equals()`
      • (2)`equalsIgnoreCase()`
      • (3)`length()`
      • (4)`indexOf()`
      • (5)`lastIndexOf()`
      • (6)`substring()`
      • (7)`trim()`
      • (8)`charAt()`
      • (9)`toUpperCase()`
      • (10)`toLowerCase()`
      • (11)`concat()`
      • (12)`replace()`
      • (13)`split()`
      • (14)`compareTo()`
        • 1. 逐字符比较:
        • 2. 长度比较:
        • 总结:
      • (15)`toCharArray()`
      • (16)`format()`
  • 二、StringBuffer 类
    • 1 基本介绍
    • 2 String 和 StringBuffer 相互转换
    • 3 StringBuffer 类的常用方法
      • (1)增: `append()`
      • (2)删: `delete()`
      • (3)`replace()`
      • (4)`indexOf()`
      • (5)`insert()`
      • (6)`length()`
  • 三、StringBuilder 类
    • 1 基本介绍
    • 2 StringBuilder 的方法和 StringBuffer 是一样的。
    • 3 String、StringBuffer 和 StringBuilder 的比较
  • 四 、String、StringBuffer 和 StringBuilder 的选择

一、String 类

1 String 类的介绍

  1. String 对象用于保存字符串,也就是一组字符序列。
  2. 字符串常量对象是用双引号括起来的字符序列。例如:“这是字符串” 、“1234” 等。
  3. 字符串的字符使用 Unicode 字符编码,一个字符(不区分字母还是汉字)占两个字节。
  4. String 类较常用构造器:
    • String s1 = new String();
    • String s2 = new String(String original);
    • String s3 = new String(char[] a);
    • String s4 = new String(char[] a, int startIndex, int count);

image-20250122140701639

  1. String 类的继承和实现关系:
    • CharSequence 接口:表示一系列可读的 char 值。它提供了对多种不同类型的 char 序列的统一、只读访问。这个接口的主要实现类包括 CharBufferStringStringBufferStringBuilder
    • Comparable 接口:在Java编程中,Comparable接口是实现对象排序的一种方式。它定义了对象的自然顺序,使得对象可以根据其内在特征进行排序。例如,整数可以按大小排序,字符串可以按字典顺序排序。Comparable接口通过其compareTo方法,允许对象自行决定如何与其他对象比较。
    • Serializable 接口:一个对象序列化的接口,一个类只有实现了Serializable接口,它的对象才能被序列化。简单理解就是,可以在网络传输。

image-20250122142849945

  1. String 类是 final 类,不能被其他的类继承。
  2. String 类有属性 private final char value[]; 用于存放字符串的内容,也就是说,字符串的内容实际上是存放在 value 数组中的。
  3. private final char value[]; :可以看到,value 数组是 final 修饰的。在java中,当final 修饰数组时,数组的引用不能被重新赋值,但数组的元素可以被修改。
public final char arr[] = {'1', '2', '3'};
char[] arr2 = {'1'};
//数组的引用不能重新赋值
//即arr不能再指向其他数组
//arr = arr2 这样就是错误的

//数组的元素可以被修改
arr[0] = '8';//这个是被允许的

2 String 对象创建的两种方式

  1. 直接将字符串赋值给 String 类型:String str1 = "xiong";
  2. 调用构造器:String str2 = new String("xiong");

两种方式的区别:

  • 方式一:先从常量池查看是否有 “xiong” 数据空间,如果有,直接指向常量池的对象;如果没有,则在常量池中创建 “xiong" 对象,然后指向,str1 最终指向的是常量池的空间地址。
  • 方式二:先在堆中创建空间,里面维护了 value 属性,指向常量池存储 ”xiong“ 的空间。如果常量池没有 “xiong” ,则会在常量池中进行创建,再让 value 指向;如果有,则 value 直接指向。
String str1 = "xiong";
String str2 = new String("xiong");

(1)创建 str1 时,首先检查常量池中是否已经存在 “xiong” ,如果不存在,就创建然后再让 str1 指向常量池中存储 “xiong” 的地址空间。如果存在,则直接指向。

(2)创建 str2 时,先在堆区创建一个 String 对象,该对象有属性 value 数组,value 数组首先检查常量池中是否已经存在 “xiong” ,如果不存在,就创建然后再让 value 指向常量池中存储 “xiong” 的地址空间。如果存在,则直接指向。

image-20250122152006774


3 测试题加深理解

(1) 例题一

String a = "xiong" + "da";
//创建了几个对象

解答: 创建了一个对象,在 使用 + 进行拼接时,编译器会进行一个优化,即上式等价于 String a = "xiongda"; 执行。

(2)例题二

String a = "xiong";
String b = "da";
String c = a + b;
//创建了几个对象

  我们使用 idea 进行debug 调试,看看 String c = a + b 是如何执行的:

首先,会进入 StringBuilder 类中的无参构造器中:

image-20250122153422921

构造器执行完之后,将进入 append 方法中,通过 super.append(str) 先将 “xiong” 添加进 StringBuilder 对象中,然后返回。

image-20250122153541904

“xiong” 完成添加之后,接着添加 “da”。

image-20250122153854807

然后调用 StringBuilder 的 toString() 方法,返回一个字符串 “xiongda”。

image-20250122153942706

(3) 例题三

  首先介绍一下 String 中的 intern() 方法:简单来说就是,如果有 String s = new String("xiong"); 如果执行 s.intern() ,那么如果常量池中已经存在 “xiong”,就会返回常量池存储 “xiong” 的空间地址,如果不存在,就会在常量池中创建,然后再返回。

image-20250122154215265

//下面的代码输出什么
String s1 = "xiong";
String s2 = "da";
String s3 = "xiongda";
String s4 = (s1 + s2).intern();
System.out.println(s3 == s4);//输出 true
System.out.println(s3.equals(s4));//输出true

4 String 类的常用方法

(1)equals()

  区分大小写,判断字符串的内容是否相等。

image-20250122173431292

使用:

String a = "xiong";
String b = new String("xiong");
System.out.println(a.equals(b));//true
//equals()方法比较的是字符串的内容是否相同

(2)equalsIgnoreCase()

  忽略大小写,判断字符串的内容是否相同。

image-20250122173719017

  字符串是区分大小写的,比如 abcAbc 这两个就是不同的字符串。但是,如果使用 equalsIgnoreCase() 方法进行比较这两个就是相等的。

String a = "abc";
String b = new String("Abc");
System.out.println(a.equalsIgnoreCase(b));//true
//equalsIgnoreCase()方法
//忽略大小写比较字符串的内容是否相同

(3)length()

  获取字符的个数,字符串的长度。

image-20250122174218012

String a = "123456";
System.out.println(a.length());//6
//字符串有6个字符,长度为6

(4)indexOf()

  • public int indexOf(int ch)

  获取字符在字符串中第一次出现的索引,索引从0开始,如果找不到,返回 -1。

image-20250122174616556

String a = "abcdefg";
int n = a.indexOf('c');
//n = 2,索引从0开始,c 的索引为2
  • public int indexOf(int ch, int formIndex)

    返回指定字符在此字符串中第一次出现的索引,从指定索引处(formIndex)开始搜索。

image-20250122175003612

String a = "123123";
//从索引为1的位置开始,获取字符在字符串中第一次出现的索引
int n = a.indexOf('1', 1);
// n = 3;从索引1开始查找,出现的第一个1的索引为3

(5)lastIndexOf()

image-20250122175330602

(6)substring()

  • public String substring(int beginIndex)

image-20250122175457482

  • public String substring(int beginIndex, int endIndex)

    截取范围为: [ b e g i n I n d e x , e n d I n d e x ) [beginIndex, endIndex) [beginIndex,endIndex)

image-20250122175517611

(7)trim()

  去除前后空格。

image-20250122175902235

String a = " abc ";
a = a.trim();// a="abc"
//去除了前后空格

(8)charAt()

  返回指定索引处的 char 值。

image-20250122180055157

String a = "abcd";
char ch = a.charAt(2);
// ch = c; 字符串索引为2的字符为c

(9)toUpperCase()

  将 String 中的所有字符转换为大写。

String a = "aBcdef";
a = a.toUpperCase();
// a = "ABCDEF";

(10)toLowerCase()

  将 String 中的所有字符转换为小写。

String a = "ABCdef";
a = a.toLowerCase();
// a = "abcdef";

(11)concat()

  将指定的字符串连接到此字符串的末尾。

image-20250122181016957

String a = "ab";
a = a.concat("c").concat("d");
// a = "abcd"

(12)replace()

image-20250122181228915

String a = "123123";
a = a.replace('2', '6');
// a = "163163"

(13)split()

  分割字符串,对于某些分割字符,我们需要转义,比如 |、\\ 等。

image-20250122181549740

String a = "My name is xiong";
String[] str = a.split(" ");
// str = {"My", "name", "is", "xiong"}

(14)compareTo()

  这个直接看源码:

public int compareTo(String anotherString) {
    // 获取当前字符串的长度
    int len1 = value.length;
    // 获取另一个字符串的长度
    int len2 = anotherString.value.length;
    // 计算两个字符串的最小长度,用于后续逐字符比较
    int lim = Math.min(len1, len2);
    // 将当前字符串的字符数组赋值给v1
    char v1[] = value;
    // 将另一个字符串的字符数组赋值给v2
    char v2[] = anotherString.value;

    // 初始化索引变量k,用于遍历字符数组
    int k = 0;
    // 遍历两个字符串的字符数组,直到最小长度lim
    while (k < lim) {
        // 获取当前索引位置的字符
        char c1 = v1[k];
        char c2 = v2[k];
        // 如果两个字符不相等
        if (c1 != c2) {
            // 返回两个字符的ASCII值差,表示字符串的字典序比较结果
            return c1 - c2;
        }
        // 如果字符相等,继续比较下一个字符
        k++;
    }
    // 如果所有字符都相等,返回两个字符串长度的差值
    // 如果长度相等,返回0,表示两个字符串相等
    // 如果当前字符串更长,返回正数,表示当前字符串大于另一个字符串
    // 如果当前字符串更短,返回负数,表示当前字符串小于另一个字符串
    return len1 - len2;
}
1. 逐字符比较:
  • 从两个字符串的起始位置开始,逐字符比较。
  • 如果在某个位置发现字符不相等,则直接返回这两个字符的ASCII值差(c1 - c2),表示字符串的字典序关系。
  • 如果字符相等,则继续比较下一个字符,直到遍历完较短字符串的长度(lim)。
2. 长度比较:
  • 如果所有字符都相等(即遍历完较短字符串后仍未分出胜负),则比较两个字符串的长度。
  • 如果当前字符串更长,返回正数;如果更短,返回负数;如果长度相等,返回0,表示两个字符串完全相等。
总结:

这段代码通过逐字符比较长度比较,实现了字符串的字典序比较,返回值表示两个字符串的大小关系:

  • 负数:当前字符串小于另一个字符串。
  • 正数:当前字符串大于另一个字符串。
  • 0:两个字符串相等。

(15)toCharArray()

image-20250122182308744

String a = "abcd";
char[] ch = a.toCharArray();
// ch = {'a', 'b', 'c', 'd'}

(16)format()

  格式化字符串:

  • %s :字符串
  • %c :字符
  • %d :整型
  • %.2f :浮点型,四舍五入保留2位小数。
//1. %s , %d , %.2f , %c 称为占位符
//2. 这些占位符由后面变量来替换
//3. %s 表示后面由字符串来替换
//4. %d 是整数来替换
//5. %.2f 表示使用小数来替换,替换后,只会保留小数点两位, 并且进行四舍五入的处理
//6. %c 使用char 类型来替换
String formatStr = "我的姓名是%s 年龄是%d,成绩是%.2f 性别是%c.希望大家喜欢我!";
String info2 = String.format(formatStr, "xiong", 18, 99.9, '男');
System.out.println("info2=" + info2);

二、StringBuffer 类

1 基本介绍

  1. java.lang.StringBuffer 代表可变的字符序列,可以对字符串内容进行增删。

  2. 很多方法与 String 相同,但 StringBuffer 是可变长度的。

  3. StringBuffer 是一个容器。

  4. StringBuffer 是 final 类,不能被继承。

  5. StringBuffer 继承了抽象类 AbstractStringBuilder。

image-20250122192704836

  1. AbstractStringBuilder 拥有 value 字符数组,StringBuffer 的字符串内容就存放在这个数组。

image-20250122192832229

  1. StringBuffer 的构造器。

image-20250122193944370

其中,字符串缓冲区就是 value 字符数组。

  • StringBuffer(String str)

    使用这个构造器时,value 的大小为 str.length() + 16


2 String 和 StringBuffer 相互转换

  在使用中,我们经常需要将 String 和 StringBuffer 进行转换,以下是转换的方式:

public class Test {
    public static void main(String[] args) {
        String str = "xiong";
        // Sting -> StringBuffer
        //1.使用构造器
        StringBuffer s1 = new StringBuffer(str);
        //2.使用 append()方法
        StringBuffer s2 = new StringBuffer();
        s2 = s2.append(str);
        
        // StringBuffer -> String
        StringBuffer s3 = new StringBuffer("da");
        //1.使用 StringBuffer 的toString()方法
        String str1 = s3.toString();
        //2.使用构造器
        String str2 = new String(s3);
    }
}

3 StringBuffer 类的常用方法

StringBuffer s = new StringBuffer("xiong");

(1)增: append()

s.append(",");
s.append("da");
// s = "xiong,da"

注意: 有很多重载的 append() 方法。具体查询可以通过 jdk 文档。

image-20250122200733790

(2)删: delete()

image-20250122200428611

StringBuffer str = new StringBuffer("xiong");
str.delete(1,3);// 删除索引为 1,2 的字符
// str = "xng"

(3)replace()

image-20250122201252064

(4)indexOf()

image-20250122201410897

image-20250122201429097

(5)insert()

  插入:

StringBuffer str = new StringBuffer("feimu");
//在索引为3的位置插入 "-"
str.insert(3,"-");
// str="fei-mu"

注意: StringBuffer 类中有很多重载的 append() 方法,有需要可以通过查阅官方文档。

image-20250122201807493

(6)length()

image-20250122201824578


三、StringBuilder 类

1 基本介绍

  1. 一个可变的字符序列。此类提供一个与 StringBuffer 兼容的 API,但不保证同步(StringBuilder 不是线程安全的)。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可以,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。

  2. 在 StringBuilder 上的主要操作是 append() 方法和 insert() 方法,可重载这些方法,以接受任意类型的数据。

  3. StringBuffer 继承了抽象类 AbstractStringBuilder。

image-20250122220855669

  1. AbstractStringBuilder 拥有 value 字符数组,StringBuffer 的字符串内容就存放在这个数组。

2 StringBuilder 的方法和 StringBuffer 是一样的。

3 String、StringBuffer 和 StringBuilder 的比较

  1. StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且方法也一样。
  2. String :不可变字符序列,效率低,但是复用率高。
  3. StringBuffer :可变字符序列,效率较高(增删)、线程安全。
  4. StringBuilder :可变字符序列、效率最高、线程不安全。
  5. String 使用注意事项:
String s = "abc";
//实际上原来的"abc"对象会被丢弃
//又产生一个字符串对象 "abcd"
s = s + "d";
//如果多次执行这样的操作,会导致大量的副本字符串对象留存在内存中
//降低效率

四 、String、StringBuffer 和 StringBuilder 的选择

使用的原则:

  1. 如果字符串存在大量的修改操作,一般使用 StringBuffer 或 StringBuilder
  2. 如果字符串存在大量的修改操作,并且在单线程的情况,使用 StringBuilder
  3. 如果字符串存在大量的修改操作,并在多线程的情况,使用 StringBuffer
  4. 如果我们的字符串很少修改,被多个对象引用,使用 String,比如配置信息等。


http://www.kler.cn/a/514869.html

相关文章:

  • linux网络 | 传输层TCP | 认识tcp报头字段与分离
  • Flink Gauss CDC:深度剖析存量与增量同步的创新设计
  • 快速学习GO语言总结
  • C#中的语句
  • 常见Arthas命令与实践
  • 小哆啦解题记:如何计算除自身以外数组的乘积
  • BUG解决:安装问题transformer_engine+pytorch
  • 基于springboot+vue的高校社团管理系统的设计与实现
  • docker ubuntu:20.04构建c++ grpc环境
  • es的date类型字段按照原生格式进行分组聚合
  • QILSTE H13-320B2W高亮白光LED灯珠 发光二极管LED
  • 如何使用CRM数据分析和洞察来支持业务决策和市场营销?
  • 开源鸿蒙开发者社区记录
  • 深入了解 Java split() 方法:分割字符串的利器
  • AI时代的网络安全:传统技术的落寞与新机遇
  • Kubernetes入门学习
  • Spring Boot 事件驱动:构建灵活可扩展的应用
  • PostgreSQL 初中级认证可以一起学吗?
  • Servlet快速入门
  • Spring Boot MyBatis Plus 版本兼容问题(记录)
  • HOW - 基于master的a分支和基于a的b分支合流问题
  • Echarts现成案例
  • 阻燃高温尼龙行业:市场潜力巨大,引领材料科学新变革
  • AI 辅助 Codebase 本地工程检索
  • Linux内核中 Netfilter 框架的用户态工具iptables(配置防火墙规则)
  • Vue | 搭建第一个Vue项目(安装node,vue-cli)