Java字符串(String、字符串拼接、原理)

文章目录

  • 一、String字符串
    • 1.1创建方式【直接赋值、new一个对象】
      • 1.1.1 使用字符串字面值直接赋值:
        • (1)字符串字面量创建String对象的转换过程
        • (2)一些方法
        • (3)说明
      • 1.1.2 使用`new`关键字创建字符串对象,将内容赋值给变量:
        • (1)`String`类有多个构造函数,其中一些常用的包括:
        • (2)说明
      • (3) 引用的是哪里的,最后又在哪里
        • 举例子
      • 1.1.3 区别
      • 1.1.4 注意点:
        • (1)字符串拼接产生新的字符串
        • (2)Java中为什么获取一个长度的时候,数组就是length,而字符串就得是length()要多加上个括号???
    • 1.2 字符串比较内容
      • 1.2.1 "==" 比较
      • 1.2.2 equals方法比较
      • 1.2.3--equalsIgnoreCase --验证码常用的方法
    • 1.3 常用方法
      • 1.3.1 遍历
      • 1.3.2 统计字符
      • 1.3.3 分割:
      • 1.3.4 截取
      • 1.3.5 替换:
      • 1.3.6 大小写转换:
      • 1.3.7 字符串转换:
      • 1.3.8 字符串格式化:
      • 1.3.9 字符串查找:
      • 1.3.10 字符串判断:
      • 1.3.11 字符串去除空格:
      • 1.3.12 字符串格式验证:
      • 1.3.13 字符串重复:
    • 1.4 名词解释
  • 二、StringBuilder构建字符串(容器)内容可变
    • 2.1 分析
      • 2.1.1 用到检测时间证明快速
        • (1)时间戳
        • (2)开始对比
    • 2.2 toString
    • 2.3 需要将StringBuilder对象转换为String对象的主要原因
    • 2.4 常用方法
    • 2.5 不会创建很多无用的空间,节约内存
    • 2.**加粗样式**6 使用CharSequence接口
    • 2.7 在Java中,为了避免创建大量的临时字符串对象,我们可以使用StringBuilder或StringBuffer类来进行字符串拼接操作。
  • 三、Stringjoiner:特定的分隔符构建字符串序列,用来连接字符串
    • 3.1 例如
    • 3.2 介绍 -- StringJoiner的出现主要是为了简化字符串连接的操作。
  • 四、字符串原理
    • 4.1 直接会复用字符串常量值或者new一个
    • 4.2 字符串拼接的底层原理
      • 在编译时已经确定了要拼接的字符串,并且没有涉及变量时,Java编译器会将连续的字符串字面值直接连接在一起

在Java中,String是一个类,用于表示字符串。它位于java.lang包下,需要进行导入语句就可以使用String类。String类用于存储和操作字符串数据。

一、String字符串

在Java中,String 是一个用于表示字符串的类。String 对象是不可变的,这意味着一旦创建了一个字符串对象,它的值就不能被改变。

String str = "Hello";
//使用字符串字面值创建字符串对象。创建了一个字符串变量`str`,并将其赋值为`"Hello"`。
String str = new String("Hello");
//通过使用`new`关键字显式地创建了一个新的`String`对象,
//内容为`"Hello"`。这种方式会在堆内存中创建一个新的字符串对象。

String str = "Hello" + "World";
//**拼接是产生一个新的字符串**,通过字符串拼接操作将`"Hello"`和`"World"`连接起来,最终赋值给`str`。这种方式会在编译时进行字符串拼接优化。

String str = String.valueOf(123);
//这句将整数`123`转换为字符串类型,并将其赋值给`str`。

1.1创建方式【直接赋值、new一个对象】

1.1.1 使用字符串字面值直接赋值:

String str1 = "Hello, World!";
(1)字符串字面量创建String对象的转换过程

字符串字面量创建String对象的转换过程主要包括在字符串常量池中进行查找和创建对象的两个步骤。
如果字符串常量池中不存在相同内容的字符串,就会创建新的字符串对象;
如果存在相同内容的字符串,就直接返回对应的字符串引用。最终,我们可以通过String类型的变量来引用这个被转化后的String对象。

(2)一些方法
String x="abc"
x.length();//字符串长度
x.charAt(int index);//返回下标字符
x.concat(y);//用来连接两个字符串

在这里插入图片描述

(3)说明

字符串字面值可以直接赋值给String类型的变量,而无需使用new关键字创建新的字符串对象。

当使用相同的字符串字面值创建多个String对象时,实际上它们会引用同一个常量池中的字符串对象。这种优化机制可以节省内存空间,并提高字符串比较的效率。

好处:节省内存空间、提高字符串比较效率

需要注意的是,这种优化只适用于字符串字面值,而不适用于使用new关键字创建的字符串对象。使用new关键字创建的字符串对象会在堆内存中单独分配空间,并不会放入字符串常量池中。

String str1 = "aaa";
String str2 = "aaa";

System.out.println(str1 == str2); // true,因为编译器会将相同的字符串常量指向同一个对象

str1和str2都是指向字符串常量池中的同一个"aaa"字符串对象,所以可以直接调用str1,无需使用new关键字创建新的对象。
在这里插入图片描述

1.1.2 使用new关键字创建字符串对象,将内容赋值给变量:

这种方式会在堆内存中创建一个新的字符串对象,无论原字符串常量池中是否已经存在相同内容的字符串,即使存在也会创建一个新的对象。

使用new关键字创建的字符串对象则会在堆内存中进行分配。

因为字符串是不可变的(immutable)对象,在大部分情况下,直接使用字符串字面量来创建字符串对象更加高效和推荐,而使用new String()的方式主要用于特定业务需求或者对字符串常量的副本进行修改的情况。

String str2 = new String("Hello, World!");
(1)String类有多个构造函数,其中一些常用的包括:
  1. String(): 创建一个空字符串。
  2. String(String original): 根据指定的字符串创建一个新的字符串。
  3. String(char[] value): 根据字符数组的内容创建一个新的字符串。
  4. String(char[] value, int offset, int count): 根据字符数组的一部分内容创建一个新的字符串。
  5. String(byte[] bytes): 根据字节数组的内容使用平台默认字符集创建一个新的字符串。
  6. String(byte[] bytes, int offset, int length): 根据字节数组的一部分内容使用平台默认字符集创建一个新的字符串。
(2)说明

使用new关键字创建字符串对象时,会在堆内存中单独为该字符串分配空间,并且不会共享字符串常量池中的对象。

每次使用new关键字创建字符串对象时,都会得到一个新的、独立的字符串对象。

String str1 = new String("aaa");
String str2 = new String("aaa");

System.out.println(str1 == str2); // false,因为使用new关键字创建的是两个独立的对象
System.out.println(str1.equals(str2)); // true,因为内容相同

它们在内存中是两个独立的对象。即使两个字符串的内容相同,它们的引用也是不同的。
由于new关键字创建的字符串对象不会共享字符串常量池中的对象,因此在进行字符串比较时,应使用equals()方法而不是简单的引用比较。

(3) 引用的是哪里的,最后又在哪里

在Java中,引用通常指的是对象的引用。
变量存储的是对象的引用,而不是对象本身。当你创建一个对象时,实际上是在内存中分配了一块空间,并返回了对该空间的引用。

在栈内存中创建了一个变量,并将该变量指向堆内存中的对象

举例子

例如1:

String str = "Hello";

在这个例子中,str是一个引用类型的变量。在栈内存中,会创建一个名为str的变量,并且该变量保存了堆内存中字符串"Hello"的地址(或者说引用)。通过该引用可以访问到堆内存中存储的字符串对象。

当我们通过new关键字创建一个字符串对象时,Java会在堆内存中分配一块空间来存储该对象,并返回其地址(引用)给我们。

例如2:

String str = new String("World");

在这个例子中,使用new关键字创建了一个字符串对象"World",并且将该对象的地址赋值给变量str。现在变量str指向堆内存中的字符串对象"World"。

需要注意的是,引用本身只是一个指向对象的地址,在栈内存中占用的空间相对较小。而实际的对象数据存储在堆内存中,占据更大的内存空间。

总结起来,引用保存在栈内存中,用于指向堆内存中的对象。通过引用可以访问、操作堆内存中的对象数据。
在这里插入图片描述

1.1.3 区别

  • 使用字符串字面值创建字符串时,如果字符串常量池中已经存在相同数值的字符串,则会直接引用该字符串,而不会创建新的对象。

  • 使用new关键字创建字符串对象时,每次都会创建一个新的字符串对象,即使字符串常量池中已经存在相同数值的字符串。

1.1.4 注意点:

(1)字符串拼接产生新的字符串

即下面的代码运行过程中是三个字符串

String hello="hello";
String world="world";
Sout(hello+world)

任何对字符串内容的更改都需要创建一个新的字符串对象来存储更改后的内容。

当我们创建一个字符串变量时,计算机会为这个字符串分配一定的内存空间,这个空间是静态分配的,也就是说这个空间的大小是固定的,不能动态地改变大小。
在这里插入图片描述

(2)Java中为什么获取一个长度的时候,数组就是length,而字符串就得是length()要多加上个括号???
在Java中,获取数组的长度使用的是length属性,、
而获取字符串的长度需要使用length()方法。

(1)这是因为数组在Java中是一个固定大小的容器,其长度是数组类型的属性,可以直接通过length属性访问。
(2)而字符串是一个对象,在Java中使用String类表示,它有一个内置的方法length()用于返回字符串的长度。

所以,数组是通过属性来获取长度,而字符串是通过方法来获取长度,因此在字符串上需要使用length()方法,并且由于方法需要调用,所以需要使用一对括号。

1.2 字符串比较内容

1.2.1 “==” 比较

(1)基本数据类型比较的是----数据值
(2)引用数据类型比较的是----地址值

import java.util.Scanner;

public class Test1{
    public static void main(String[] args) {
        String str1 = "aaa";
        String str2 = "aaa";
        System.out.println(str1 == str2); // true,因为编译器会优化,将相同的字符串引用指向同一个对象

        String str3 = new String("aaa");
        System.out.println(str1 == str3); // false,使用new关键字创建新的对象,所以引用地址不同
        byte[] bytes = {97, 97, 97};
        String str4 = new String(bytes);
        System.out.println(str1 == str4); // false,通过字节数组创建的新对象,引用地址不同
        System.out.println(str3 == str4); // false,str3和str4是不同的对象

        Scanner sc = new Scanner(System.in);
        String str5 = sc.next();//控制台输入aaa
        System.out.println(str1 == str5); // false,用户输入的字符串是新的对象
        System.out.println(str3 == str5); // false
        System.out.println(str4 == str5); // false
        
        sc.close();
    }
}

1.2.2 equals方法比较

String str1 = "hello";
String str2 = "hello";
System.out.println(str1.equals(str2));//true

equals方法用于比较两个字符串的内容是否相等

import java.util.Arrays;
import java.util.Objects;
import java.util.Scanner;

public class Test1{
    public static void main(String[] args) {
        String str1 = "aaa";
        String str2 = "aaa";
        System.out.println(str1.equals(str2));

        String str3 = new String("aaa");
        System.out.println(str1.equals(str3));

        byte[] bytes = {97, 97, 97};
        String str4 = new String(bytes);
        System.out.println(str1.equals(str4));
        System.out.println(str3.equals(str4));

        Scanner sc = new Scanner(System.in);
        String str5 = sc.next();
        for (String s : Arrays.asList(str1, str3, str4)) {
            System.out.println(Objects.equals(s, str5));
        }

        sc.close();
    }
}

1.2.3–equalsIgnoreCase --验证码常用的方法

equalsIgnoreCase方法用于比较两个字符串的内容是否相等,忽略大小写

1.3 常用方法

1.3.1 遍历

String str = "hello";
//length() - 返回字符串的长度
for(int i=0;i<str.length();i++){
	//charAt(int index) - 返回指定索引处的字符
    System.out.println(str.charAt(i));
}

另一种常用的方法是使用增强的for循环(也称为foreach循环)来遍历字符串中的每个字符。

String str = "Hello, World!";
for (char ch : str.toCharArray()) {
    System.out.println(ch);
}

toCharArray()是Java中String类的一个方法,用于将字符串转换为字符数组。
把字符串str转换成字符数组是因为在Java中,字符串是一个对象,而字符数组是字符的有序集合。
通过将字符串转换为字符数组,可以按照字符的顺序逐个遍历和访问每个字符元素。

为了更高效地遍历字符串每个元素,通常建议使用字符数组(char array)或者 StringBuilder 类。字符数组是可变的,可以直接修改其中的元素,而 StringBuilder 类提供了可变的字符串序列,可以高效地进行字符串操作。

直接访问字符串中的每个字符,而无需创建新的字符串对象:

使用字符数组:

String str = "Hello";
char[] charArray = str.toCharArray();

for (char ch : charArray) {
    System.out.println(ch);
}

使用 StringBuilder 类:

String str = "World";
StringBuilder sb = new StringBuilder(str);

for (int i = 0; i < sb.length(); i++) {
    char ch = sb.charAt(i);
    System.out.println(ch);
}

1.3.2 统计字符

public class CharacterCount {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        System.out.print("请输入一个字符串: ");
        String str = scanner.nextLine();
        
        // 统计大写字母、小写字母和数字字符的次数
        int uppercaseCount = 0;
        int lowercaseCount = 0;
        int digitCount = 0;
        
        // 遍历字符串中的每个字符
        for (char ch : str.toCharArray()) {
            if (Character.isUpperCase(ch)) {
                uppercaseCount++;
            } else if (Character.isLowerCase(ch)) {
                lowercaseCount++;
            } else if (Character.isDigit(ch)) {
                digitCount++;
            }
        }
        
        System.out.println("大写字母个数: " + uppercaseCount);
        System.out.println("小写字母个数: " + lowercaseCount);
        System.out.println("数字个数: " + digitCount);
    }

1.3.3 分割:

使用split()方法将一个字符串分割成多个子字符串。

// 字符串分割
String sentence = "Java is a programming language";
String[] words = sentence.split(" ");
System.out.println("分割后的字符串数组:");
for (String word : words) {
   System.out.println(word);
}

1.3.4 截取

public String substring(int beginIndex) 
public String substring(int beginIndex, int endIndex)//左闭右开
// 字符串截取
String originalString = "Hello World";
String substring = originalString.substring(6);
System.out.println("截取子字符串:" + substring);//截取子字符串:World

1.3.5 替换:

方法的返回值是替换的值

public String replace(char oldChar, char newChar)

使用replace()方法将一个字符串中的某个子串替换为另一个字符串。

// 字符串替换
String originalSentence = "I love apples";
String replacedSentence = originalSentence.replace("apples",
                "oranges");
System.out.println("替换后的字符串:" + replacedSentence);//替换后的字符串:I love oranges

1.3.6 大小写转换:

  • 使用toUpperCase()方法将字符串中所有字符转换为大写。
  • 使用toLowerCase()方法将字符串中所有字符转换为小写。
// 字符串大小写转换
String lowercaseString = "hello world";
String uppercaseString = lowercaseString.toUpperCase();
System.out.println("转换为大写字母:" + uppercaseString);//转换为大写字母:HELLO WORLD

1.3.7 字符串转换:

  • 使用valueOf()方法将其他数据类型转换为字符串。
  • 使用parseXxx()方法将字符串转换为其他数据类型。
// 字符串转换
int number = 42;
String numberString =String.valueOf(number);
System.out.println("转换为字符串:" + numberString);//转换为字符串:42

1.3.8 字符串格式化:

  • 使用String.format()方法将数据格式化成特定的字符串形式。
// 字符串格式化
String formattedString = String.format("The value of PI is approximately %.2f", Math.PI);
System.out.println("格式化后的字符串:" + formattedString);//格式化后的字符串:The value of PI is approximately 3.14

1.3.9 字符串查找:

  • 使用indexOf()方法查找指定字符或子字符串在字符串中的位置。
// 字符串查找
String phrase = "Java programming language";
int index = phrase.indexOf("programming");
System.out.println("'programming'第一次出现的位置:" + index);//'programming'第一次出现的位置:5

使用lastIndexOf()方法查找指定字符或子字符串在字符串中的位置。

1.3.10 字符串判断:

使用startsWith()方法判断字符串是否以指定的前缀开头。

// 字符串判断
String startsWithExample = "Hello World";
boolean startsWithHello = startsWithExample.startsWith("Hello");
System.out.println("是否以'Hello'开头:" + startsWithHello);//是否以'Hello'开头:true

使用endsWith()方法判断字符串是否以指定的后缀结尾。

1.3.11 字符串去除空格:

使用trim()方法去除字符串两端的空格。

// 字符串去除空格
String stringWithSpaces = " Trim me ";
String trimmedString = stringWithSpaces.trim();
System.out.println("去除空格后的字符串:" + trimmedString);

1.3.12 字符串格式验证:

使用正则表达式和matches()方法验证字符串是否符合特定的格式要求。

// 字符串格式验证
String email = "example@example.com";
boolean isValidEmail = email.matches("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}");
System.out.println("是否是有效的邮箱地址:" + isValidEmail);

1.3.13 字符串重复:

使用repeat()方法将一个字符串重复指定次数。

// 字符串重复
String repeatedString = "Java".repeat(3);
System.out.println("重复字符串:" + repeatedString);
// 输出:重复字符串:JavaJavaJava
}

1.4 名词解释

  • (1)字符串常量池:字符串常量池是Java中的一个特殊存储区域,用于存储字符串字面值。当使用字符串字面值创建字符串时,如果字符串常量池中已经存在相同数值的字符串,则会直接引用该字符串,而不会创建新的对象。

    可以提高内存的利用率和效率。而通过new关键字创建的字符串对象不会被保存在字符串常量池中。

  • (2)字面量:在编程中,字面量是表示固定值的符号表示法。在Java中,字符串字面值是指直接使用双引号括起来的字符串文本,例如"Hello, World!"就是一个字符串字面值。

当我们使用字符串字面值创建字符串对象时,Java会先在字符串常量池中查找是否存在相等的字符串。如果存在,则返回常量池中对应的引用;如果不存在,则在常量池中创建新的字符串并返回引用。

  • (3)堆内存(Heap Memory):除了字符串常量池外,Java中的字符串对象也可以存储在堆内存中。当我们使用关键字new来创建一个字符串对象时,该对象会被存储在堆内存中,并且不会进入字符串常量池。每次通过new创建的字符串对象都会在堆内存中分配新的空间,即使字符串的内容相同。

  • (4)长度为0的字符串和null的

  • 【1】空串
    空串是指长度为0的字符串,也就是不包含任何字符的字符串。在Java中,空串可以用双引号""表示。

  1. 使用双引号表示空字符串:
String emptyString = "";
  1. 使用String类的构造函数创建一个空字符串对象:
String emptyString = new String();
  1. 证明:
if(str.length()==0)
if(str.equals(""))
str.isEmpty()

【2】Null是一个特殊的值
在Java中,null是一个特殊的关键字,表示一个变量不引用任何对象。当一个对象引用被赋予null值时,表示该引用不指向任何有效的对象实例。在这种情况下,任何对该引用的方法调用都会导致NullPointerException异常。

if(str==null)
if(str!=null&&str.length()!=0)

if (str == null) 检查字符串引用是否指向null,即字符串对象是否未实例化。如果str为null,表示字符串对象不存在。

if (str != null && str.length() != 0) 则首先检查字符串引用是否不为null,然后再检查字符串的长度是否不为0。这个条件用于确保字符串既不为null,又不是空串。

因此,第一个条件主要检查字符串是否为null,而第二个条件则进一步确保字符串既不为null,又不是空串

null	这个值可以是任何类型的对象,包括字符串、数组、类等等。当一个对象被赋值为null时,
它就不再指向任何对象,也就是说它不再引用任何对象,因此也就无法访问该对象的任何属性或方法。
  • 【3】区别
    空串是一个长度为0的字符串,表示一个有效的字符串对象,而null表示一个变量未引用任何对象。
    在Java中,空串是一个字符串对象,而null是一个特殊的关键字,表示缺少对象引用。

二、StringBuilder构建字符串(容器)内容可变

StringBuilder是Java中用于处理可变字符串的类。它位于java.lang包下。
其参与到的字符串进行修改,不会创建新的字符串对象,这在需要频繁修改字符串时可以提高性能。
在这里插入图片描述

2.1 分析

空参构造: public StringBuilder() 创建一个空白可变字符串对象,不含有任何内容
有参构造: public StringBuilder(String str) 根据字符串的内容,来创建可变字符串对象

- StringBuilder():创建一个空的StringBuilder对象,初始容量为16个字符。
- StringBuilder(CharSequence seq):创建一个StringBuilder对象,并将指定的字符序列初始化为其内容。
- StringBuilder(int capacity):创建一个指定初始容量的StringBuilder对象。
- StringBuilder(String str):创建一个StringBuilder对象,并将指定的字符串初始化为其内容。

在这里插入图片描述

StringBuilder sb = new StringBuilder(); // 默认创建一个长度为16的字符数组
System.out.println("最多能存储的字符数:" + sb.capacity()); // 输出最多能存储的字符数
sb.append("Hello, World!"); // 向StringBuilder中添加字符串
System.out.println("实际存储的字符数:" + sb.length()); // 输出实际存储的字符数

2.1.1 用到检测时间证明快速

(1)时间戳

要获取Java代码的运行时间,可以使用System.currentTimeMillis()方法。在给定的代码中,这个选择了System.currentTimeMillis()方法是正确的。这个方法返回自1970年1月1日以来的毫秒数,可以用来计算代码的执行时间。

使用System.currentTimeMillis()方法的返回值保存在一个变量中,然后在代码执行完毕后再次调用System.currentTimeMillis()方法,将两个时间戳相减,就可以得到代码的执行时间。

public static void main(String[] args) {
   long startTime = System.currentTimeMillis();
   //此处需要检验操作事件的执行的雨具块
   long endTime = System.currentTimeMillis();
   long executionTime = endTime - startTime;
   System.out.println("代码执行时间:" + executionTime + "毫秒");
}
(2)开始对比

【1】普通的拼接操作:
每次字符串拼接操作都会创建一个新的字符串对象

public static void main(String[] args) {
    long startTime = System.currentTimeMillis();
    String str = "";
    for (int i = 1; i < Math.pow(10, 5); i++) {
        str += "abc ";
    }
    System.out.println(str);
    System.out.println(str.toString());
    System.currentTimeMillis();
    long endTime = System.currentTimeMillis();
    long executionTime = endTime - startTime;
    System.out.println("代码执行时间:" + executionTime + "毫秒");
}

在这里插入图片描述
【2】StringBuilder拼接:
内部维护了一个可变的字符数组用于存储字符串,每次拼接只需修改数组中的内容,而不需要创建新的字符串对象

public static void main(String[] args) {
    //StringBuilder拼接
    StringBuilder str = new StringBuilder();
    long startTime = System.currentTimeMillis();
    for (int i = 0; i < Math.pow(10, 5); i++) {
        str.append("abc ");
    }
    str.append(123).append(123123);//链式调用
    System.out.println(str);
    System.out.println(str.toString());
    long endTime = System.currentTimeMillis();
    long executionTime = endTime - startTime;
    System.out.println("StringBuilder拼接-代码执行时间:" + executionTime + "毫秒");
    }

在这里插入图片描述

2.2 toString

StringBuilder 用于动态构建字符串,而 toString() 方法用于将 StringBuilder 对象转换为一个字符串。当你需要将 StringBuilder 对象的内容作为一个字符串来处理时,就需要使用 toString() 方法。

对于StringBuilder对象,调用toString()方法会返回包含StringBuilder对象内容的String对象。这样可以方便地在StringBuilder和String之间进行转换,以便进行字符串的进一步处理或者与其他String对象进行拼接等操作。

2.3 需要将StringBuilder对象转换为String对象的主要原因

StringBuilder对象用于处理可变的字符串,允许在不创建新的字符串对象的情况下进行字符串操作,这在需要频繁修改字符串内容时非常高效。但有时候需要将StringBuilder对象转换为String对象,比如当需要将最终的字符串结果传递给需要String类型参数的方法时,或者希望保留字符串的不可变性。

String不可变

public static void main(String[] args) {
    String str = new String("abc");
    System.out.println(str);
    System.out.println(str.hashCode());
    str = "123";
    System.out.println(str);
    System.out.println(str.hashCode());
    str = "abc";
    System.out.println(str.hashCode()); 
}

在这里插入图片描述

2.4 常用方法

  • append(String str):将指定的字符串追加到StringBuilder对象的末尾。
  • insert(int offset, String str):在指定位置插入指定的字符串。
  • delete(int start, int end):删除指定范围内的字符。
  • replace(int start, int end, String str):将指定范围内的字符替换为指定的字符串。
  • reverse():将StringBuilder对象中的字符顺序反转。-- 常用于对称问题
  • toString():将StringBuilder对象转换为字符串String。
  • length():获取StringBuilder对象中的字符数量。
public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    System.out.print("请输入字符串:");
    String inputString = scanner.nextLine();
    //翻转
    StringBuilder stringBuilder = new StringBuilder(inputString);//或者用append()方法
    stringBuilder.reverse();
    
    //tostring
    String reversedString = stringBuilder.toString();
	System.out.println("翻转后的字符串:" + reversedString);
    }

链式编程一步到位 StringBuilder stringBuilder= new StringBuilder(inputString).reverse().toString();

StringBuilder对象调用了控制台输出语句时,java底层会自动调用StringBuilder中重写后的toString()方法

StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" World");
system.out.println(sb); //Java在底层的处理,打印对象不是地址值而是属性值
sb="123";
System.out.println(sb); //123
System.out.println(sb.toString()); // 输出:Hello World

sb.insert(6, "Java");
System.out.println(sb.toString()); // 输出:Hello Java World

sb.delete(0, 5);
System.out.println(sb.toString()); // 输出:Java World

sb.replace(0, 5, "Hello");
System.out.println(sb.toString()); // 输出:Hello World

sb.reverse();
System.out.println(sb.toString()); // 输出:dlroW olleH

StringBuilder sb2 = new StringBuilder("Hello");
System.out.println(sb2.toString()); // 输出:Hello

StringBuilder sb3 = new StringBuilder(10);
System.out.println(sb3.toString()); // 输出:空字符串

StringBuilder sb4 = new StringBuilder("Hello World");
System.out.println(sb4.toString()); // 输出:Hello World

2.5 不会创建很多无用的空间,节约内存

在Java中,StringBuilder用于创建可变的字符串对象,适合在需要频繁修改字符串内容的场景下使用。与String不同,StringBuilder不会创建新的对象,而是直接在原有对象上进行修改,从而提高了性能和节约了内存。

public class StringBuilderExample {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        
        sb.append("Hello");
        sb.append(" ");
        sb.append("World");
        
        String result = sb.toString();
        System.out.println(result);  // 输出: Hello World
    }
}

在这个示例中,我们使用StringBuilder的append方法来拼接字符串,最后通过toString方法将其转换为String对象。这样做可以避免创建多个中间String对象,从而节约内存。

2.加粗样式6 使用CharSequence接口

CharSequence是Java中的一个接口,它是许多字符串类型的通用父接口,包括StringStringBuilderStringBuffer。它定义了一些基本的方法,如length()charAt(int index)subSequence(int start, int end),这些方法在所有实现了CharSequence接口的类中都可以使用。

public class CharSequenceExample {
    public static void main(String[] args) {
        CharSequence cs1 = "Hello, World!";
        CharSequence cs2 = new StringBuilder("Hello, StringBuilder!");
        CharSequence cs3 = new StringBuffer("Hello, StringBuffer!");

        printCharSequence(cs1);
        printCharSequence(cs2);
        printCharSequence(cs3);
    }

    public static void printCharSequence(CharSequence cs) {
        System.out.println("Length: " + cs.length());
        System.out.println("First character: " + cs.charAt(0));
        System.out.println("Subsequence (0, 5): " + cs.subSequence(0, 5));
    }
}

在这个示例中,我们创建了三个不同类型的CharSequence对象,并使用一个通用的方法来打印它们的长度、首字符和子序列。这样可以展示CharSequence接口的多态性。

2.7 在Java中,为了避免创建大量的临时字符串对象,我们可以使用StringBuilder或StringBuffer类来进行字符串拼接操作。

这种方式利用了可变字符序列的特性,在内部只会创建一个StringBuilder(或StringBuffer)对象,并在这个对象中逐步修改和拼接字符串,避免了频繁地创建临时字符串对象,从而节约了内存空间。

三、Stringjoiner:特定的分隔符构建字符串序列,用来连接字符串

StringJoiner类是在Java 8中引入的,作为Java标准库的一部分。
它提供了一种简便的方式来连接多个字符串,并且在连接过程中可以指定分隔符、前缀和后缀等信息。

StringJoiner用于以特定的分隔符构建字符串序列。它提供了一种方便的方式来连接字符串,并控制它们之间的分隔符。通过指定分隔符和可选的前缀和后缀,可以添加多个字符串,并使用指定的分隔符将它们转换为单个字符串。

public static void main(String[] args) {
    int[] arr = { 1, 'A', 3, 4 };
    String strs = arrToString(arr);
    System.out.println(strs); // [1, A, 3, 4]
}

public static String arrToString(int[] arr) {
    StringJoiner sj = new StringJoiner(", ", "[", "]");
    for (int c : arr) {
       sj.add(String.valueOf(c));
    }
    return sj.toString();
}

3.1 例如

public static void main(String[] args) {
    List<String> strings = Arrays.asList("apple", "banana", "orange");
        
    StringJoiner joiner = new StringJoiner(", "); // 使用逗号和空格作为分隔符
    for (String s : strings) {
        joiner.add(s);
    }

    String result = joiner.toString();
    System.out.println(result); // 输出:apple, banana, orange
}

我们首先创建了一个StringJoiner对象 joiner,并指定了逗号和空格作为分隔符。然后遍历字符串列表,将每个字符串都添加到StringJoiner对象中。最后调用toString()方法获取拼接后的字符串结果。

3.2 介绍 – StringJoiner的出现主要是为了简化字符串连接的操作。

public class StringJoiner {
    // 构造函数:创建一个新的StringJoiner对象
    public StringJoiner(CharSequence delimiter)
    
    // 构造函数:创建一个新的StringJoiner对象,指定分隔符和前缀、后缀
    public StringJoiner(CharSequence delimiter, CharSequence prefix, CharSequence suffix)

    // 添加一个元素到StringJoiner中
    public StringJoiner add(CharSequence element)
    
    // 合并另一个StringJoiner对象到当前对象中
    public StringJoiner merge(StringJoiner other)
    
    // 获取当前StringJoiner对象中的字符串结果
    public String toString()
}

StringJoiner类提供了多个构造函数来创建实例。第一个构造函数传入一个分隔符 delimiter,用于指定在连接字符串时使用的分隔符。第二个构造函数还可以传入一个前缀 prefix 和一个后缀 suffix,用于在最终的连接结果前面和后面添加额外的字符串。

通过调用add()方法,可以将一个元素添加到StringJoiner对象中。可以连续调用add()方法以添加多个元素。

使用merge()方法可以合并另一个StringJoiner对象的内容到当前对象中。

StringJoiner sj1 = new StringJoiner(",");
sj1.add("apple");
sj1.add("banana");

StringJoiner sj2 = new StringJoiner(":");
sj2.add("car");
sj2.add("bike");

sj1.merge(sj2);
System.out.println(sj1.toString()); // 输出:apple,banana,car:bike

最后,调用toString()方法可以获取StringJoiner对象中连接后的字符串结果。

StringJoiner sj = new StringJoiner("-");
sj.add("Java");
sj.add("Python");
sj.add("C++");

String result = sj.toString();
System.out.println(result); // 输出:Java-Python-C++

再例如:

public class Main {
    public static void main(String[] args) {
        StringJoiner stringJoiner = new StringJoiner(", ", "[", "]"); 
        
        stringJoiner.add("Apple"); // Add "Apple" to the StringJoiner
        stringJoiner.add("Banana"); // Add "Banana" to the StringJoiner
        stringJoiner.add("Orange"); // Add "Orange" to the StringJoiner
        
        String result = stringJoiner.toString(); // Get the string result of the StringJoiner
        
        System.out.println(result); // Output: [Apple, Banana, Orange]
    }
}

四、字符串原理

4.1 直接会复用字符串常量值或者new一个

Java中的字符串存储内存原理可以简单归纳为:由于字符串一旦创建,就不能修改它的值,其创建通过字符串常量池实现字符串的共享和复用,提高性能和节省内存空间;而使用new关键字创建的字符串对象则会在堆内存中分配独立的空间。

4.2 字符串拼接的底层原理

  1. 如果没有变量参与,都是字符串直接相加,编译之后就是拼接之后的结果,会复用字符串池中的字符串。
  2. 如果有变量参与,每一行拼接的代码,都会在内存中创建新的字符串,浪费内存。
public class StringConcatenation {
    public static void main(String[] args) {
        // 没有变量参与的字符串拼接
        String str1 = "Hello, " + "world!";
        System.out.println(str1); // 输出: Hello, world!

        // 有变量参与的字符串拼接
        String str2 = "Hello, ";
        String str3 = str2 + "world!";
        System.out.println(str3); // 输出: Hello, world!
    }
}

在第一个例子中,字符串拼接在编译时完成,结果是一个常量字符串,存储在字符串池中。而在第二个例子中,字符串拼接在运行时完成,会在内存中创建新的字符串对象。

在编译时已经确定了要拼接的字符串,并且没有涉及变量时,Java编译器会将连续的字符串字面值直接连接在一起

这种情况下的字符串拼接操作会在编译时被优化为一个单独的字符串常量。

例如,以下代码片段:

String str = "Hello" + ", " + "World!";

在编译时,会被优化为:

String str = "Hello, World!";

请注意,==这种优化只适用于字符串字面值的拼接,而不适用于包含变量的字符串拼接。==在涉及变量的情况下,仍然建议使用 StringBuilder 或 StringBuffer 来进行字符串拼接,以避免频繁创建临时对象和提高性能。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL:TABLE_SCHEMA及其应用

MySQL TABLE_SCHEMA及其应用 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28550263/ar…

285个地级市出口产品质量及技术复杂度(2011-2021年)

出口产品质量与技术复杂度&#xff1a;衡量国家竞争力的关键指标 出口产品质量是衡量国内企业生产的产品在国际市场上竞争力的重要标准。它不仅要求产品符合国际标准和目标市场的法律法规&#xff0c;而且需要保证产品质量的稳定性和可靠性。而出口技术复杂度则进一步体现了一…

龙迅LT8641UXE HDMI四进一出切换开关,支持标准HDMI 2.0内置MCU

龙迅LT8641UXE描述&#xff1a; Lontium LT8641UX HDMI2.0开关具有符合HDMI2.0/1.4规范的4&#xff1a;1开关&#xff0c;最大6Gbps高速数据速率&#xff0c;自适应均衡RX输入和预先强调的TX输出支持长电缆应用&#xff0c;没有XTAL板上节省BOM成本。LT8641UX HDMI2.0开关自动…

C++之goto陈述

关键字 goto用于控制程式执行的顺序&#xff0c;使程式直接跳到指定标签(lable) 的地方继续执行。 形式如下 标签可以是任意的识别字&#xff0c;后面接一个冒号。 举例如下 #include <iostream>int main() {goto label_one;label_one: {std::cout << "Lab…

数字人直播时代来了!数字人直播系统搭建,AI虚拟数字人直播系统源码部署

数字人直播系统这是一种利用人工智能技术&#xff0c;实现自动化生成真实人物直播销售商品的综合性解决方案。 一、目前数字人直播支持的平台&#xff1a; 抖音、快手、视频号、小红书、淘宝、支付宝生活号、TikTok、阿里国际站等。 技术栈 数据库&#xff1a;mysql5.7 技术搭…

搜维尔科技:OptiTrack在NAB2024展示了一系列业界领先的媒体技术

广泛的显示和动作捕捉跟踪技术组合涵盖无与伦比的室内和室外 LED 解决方案、前沿技术演示以及最新的软件和硬件产品 可视化技术领域的全球领导者 Planar及其附属公司 3D 跟踪系统的全球领导者OptiTrack宣布&#xff0c;两家公司将在 2024 年全国广播协会 (NAB) 展会上展示其最全…

新火种AI|OpenAI的CEO又有新动作?这次他成立了AI健康公司

作者&#xff1a;一号 编辑&#xff1a;美美 AI技术即将改变医疗健康市场。 就在前两天&#xff0c;人工智能和医疗健康领域迎来了一个重要时刻。OpenAI的CEO萨姆阿尔特曼&#xff08;Sam Altman&#xff09;与Thrive Global的CEO阿里安娜赫芬顿&#xff08;Arianna Huffing…

Linux网络命令:网络工具socat详解

目录 一、概述 二、基本用法 1、基本语法 2、常用选项 3、获取帮助 三、用法示例 1. 监听 TCP 端口并回显接收到的数据 2. 通过 TCP 端口转发数据到 UNIX 套接字 3. 将文件内容发送到 TCP 端口&#xff1a; 4. 使用伪终端进行串行通信 5、启动一个TCP服务器 6、建…

go-redis源码解析:连接池原理

1. 执行命令的入口方法 redis也是通过hook执行命令&#xff0c;initHooks时&#xff0c;会将redis的hook放在第一个 通过hook调用到process方法&#xff0c;process方法内部再调用_process 2. 线程池初始化 redis在新建单客户端、sentinel客户端、cluster客户端等&#xff0c…

Apache Flink核心特性应用场景

Flink的定义 Apache Flink是一个分布式处理引擎&#xff0c;用于处理 无边界数据流&#xff0c; 有边界数据流上金秀贤有状态的计算。Flink能在所有常见的集群环境中运行&#xff0c;并能以内存速度和任意规模进行计算如下Flink官网的一张图 Flink 与Spark的区别 Flink 中处…

《大语言模型的临床和外科应用:系统综述》

这篇题为《大语言模型的临床和外科应用&#xff1a;系统综述》的文章对大语言模型&#xff08;LLM&#xff09;目前在临床和外科环境中的应用情况进行了全面评估。 大语言模型&#xff08;LLM&#xff09;是一种先进的人工智能系统&#xff0c;可以理解和生成类似人类的文本。…

理解 LibTorch 的工作流程

深入理解 LibTorch 的工作流程 摘要 本文详细介绍了 LibTorch 的工作流程&#xff0c;包括模型定义、数据准备、训练、评估和推理。通过具体的伪代码示例&#xff0c;帮助读者深入理解 LibTorch 的基本原理和使用方法。 关键字 LibTorch, 深度学习, 动态计算图, 自动微分, …

Sharding-JDBC分库分表之SpringBoot主从配置

Sharding-JDBC系列 1、Sharding-JDBC分库分表的基本使用 2、Sharding-JDBC分库分表之SpringBoot分片策略 3、Sharding-JDBC分库分表之SpringBoot主从配置 前言 在开发中&#xff0c;如果对数据库的读和写都在一个数据服务器中操作&#xff0c;面对日益增加的访问量&#x…

HI3559AV100四路IMX334非融合拼接8K视频记录

下班无事&#xff0c;写篇博客记录海思hi3559av100四路4K视频采集拼接输出8K视频Demo 一、准备工作&#xff1a; 软件&#xff1a;Win11系统、VMware虚拟机Ubuntu14、Hitool、Xshell等 硬件&#xff1a;HI3559AV100开发板4路imx334摄像头、串口线、电源等 附硬件图&#xff1…

阿里发布大模型发布图结构长文本处理智能体,超越GPT-4-128k

随着大语言模型的发展&#xff0c;处理长文本的能力成为了一个重要挑战。虽然有许多方法试图解决这个问题&#xff0c;但都存在不同程度的局限性。最近&#xff0c;阿里巴巴的研究团队提出了一个名为GraphReader的新方法&#xff0c;通过将长文本组织成图结构&#xff0c;并利用…

《RWKV》论文笔记

原文出处 [2305.13048] RWKV: Reinventing RNNs for the Transformer Era (arxiv.org) 原文笔记 What RWKV(RawKuv):Reinventing RNNs for the Transformer Era 本文贡献如下&#xff1a; 提出了 RWKV 网络架构&#xff0c;结合了RNNS 和Transformer 的优点&#xff0c;同…

【GC 垃圾回收算法和回收器】

作者&#xff1a;ofLJli 链接&#xff1a;https://juejin.cn/post/7003213289425633287?searchId20240709085629749958B21D886D4E67D4 来源&#xff1a;稀土掘金 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 概述 在JVM中主要的结构为&…

工作助手VB开发笔记(1)

1.思路 1.1 样式 样式为常驻前台的一个小窗口&#xff0c;小窗口上有三到四个按钮&#xff0c;为一级功能&#xff0c;是当前工作内容的常用功能窗口&#xff0c;有十个二级窗口&#xff0c;为选中窗口时的扩展选项&#xff0c;有若干后台功能&#xff0c;可选中至前台 可最…

C++入门基础(1)

因为6月中旬学校事情多&#xff0c;许久未更新&#xff0c;让我们继续学习吧&#xff01; 目录 前言&#xff1a; 一、命名空间&#xff1a; 1、定义&#xff1a; 2、使用&#xff1a; 3、访问命名空间域: 二、C输入、输出函数&#xff1a; 1、输入函数&#xff1a; 2、输出…

【正点原子i.MX93开发板试用连载体验】项目计划和开箱体验

本文最早发表于电子发烧友&#xff1a;【   】【正点原子i.MX93开发板试用连载体验】基于深度学习的语音本地控制 - 正点原子学习小组 - 电子技术论坛 - 广受欢迎的专业电子论坛! (elecfans.com)https://bbs.elecfans.com/jishu_2438354_1_1.html 有一段时间没有参加电子发…