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();//控制台输入aaaSystem.out.println(str1 == str5); // false,用户输入的字符串是新的对象System.out.println(str3 == str5); // falseSystem.out.println(str4 == str5); // falsesc.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();//tostringString 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 Worldsb.insert(6, "Java");
System.out.println(sb.toString()); // 输出:Hello Java Worldsb.delete(0, 5);
System.out.println(sb.toString()); // 输出:Java Worldsb.replace(0, 5, "Hello");
System.out.println(sb.toString()); // 输出:Hello Worldsb.reverse();
System.out.println(sb.toString()); // 输出:dlroW olleHStringBuilder sb2 = new StringBuilder("Hello");
System.out.println(sb2.toString()); // 输出:HelloStringBuilder 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 StringJoinerstringJoiner.add("Banana"); // Add "Banana" to the StringJoinerstringJoiner.add("Orange"); // Add "Orange" to the StringJoinerString result = stringJoiner.toString(); // Get the string result of the StringJoinerSystem.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 来进行字符串拼接,以避免频繁创建临时对象和提高性能。

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

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

相关文章

接口测试(1)

什么是接口测试 路线&#xff1a; 项目介绍 URL&#xff1a;统一资源定位符 HTTP协议 请求URL 请求行 请求方法 post/put 请求行 请求数据类型 content-type json 请求数据 请求体 响应状态码 响应行 响应数据类型 content-type json 响应数据 请响应体 用户名&#xf…

Mybatis Plus 3.X版本的insert填充自增id的IdType.ID_WORKER策略源码分析

总结/朱季谦 某天同事突然问我&#xff0c;你知道Mybatis Plus的insert方法&#xff0c;插入数据后自增id是如何自增的吗&#xff1f; 我愣了一下&#xff0c;脑海里只想到&#xff0c;当在POJO类的id设置一个自增策略后&#xff0c;例如TableId(value "id",type …

Git 命令行快速入门

前言 &#xff08;1&#xff09;新手个人建议使用TortoiseGit这类图形化界面来上手学习。 &#xff08;2&#xff09;如果一定需要用命令行进行操作&#xff0c;可以按照B站&#xff1a;程式与网页开发者必备技能&#xff01;Git 和 GitHub 零基础快速上手&#xff0c;轻松掌握…

干货:高水平论文写作思路与方法

前言:Hello大家好,我是小哥谈。高水平论文的写作需要扎实的研究基础和严谨的思维方式。同时,良好的写作技巧和时间管理也是成功的关键。本篇文章转载自行业领域专家所写的一篇文章,希望大家阅读后可以能够有所收获。🌈 目录 🚀1.依托事实/证据,通过合理的逻辑,…

汇川CodeSysPLC教程03-2-14 与HMI通信

硬件连接 PLC与HMI连接采用何种连接方式&#xff0c;通常是参考双方支持哪些接口。PLC&#xff08;可编程逻辑控制器&#xff09;与HMI&#xff08;人机界面&#xff09;之间的通讯方式主要有以下几种&#xff1a; 串行通讯&#xff08;Serial Communication&#xff09;&…

Git本地仓库的搭建与使用

目录 一、前言 二、Linux下搭建 git 仓库 三、Windows下搭建 git 仓库 一、前言 做项目时&#xff0c;我们常常需要将自己的代码进行托管&#xff0c;但有时候 Github 的速度属实叫人流泪。有的人会选择 Gitee 等进行托管代码&#xff0c;这当然是可以的。那如果没有其他代码…

前端图表库G2快速上手

文档地址&#xff1a; https://g2-v3.antv.vision/zh/docs/manual/getting-started/ https://g2.antv.antgroup.com/ 安装&#xff1a; pnpm i antv/g2在vue3中使用&#xff1a; <script setup> import {Chart} from antv/g2; import {onMounted} from "vue"…

LeetCode(2)-反转链表、删除链表中等于val的节点、返回链表中的中间节点

一、反转链表 . - 力扣&#xff08;LeetCode&#xff09; 解法1&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ typedef struct ListNode ListNode; struct ListNode* reverseList(struct ListN…

MySQL架构优化及SQL优化

变更项目的整体架构是性能收益最大的方式。主要涉及两方面&#xff0c;一方面是从整个项目角度&#xff0c;引入一些中间件优化整体性能&#xff0c;另一方面是调整MySQL的部署架构&#xff0c;确保能承载更大的流量访问&#xff0c;提高数据层的整体吞吐。 1. 引入缓存中间件…

手把手教你玩转AD9361数字调制解调系列(四) ----纯PL逻辑实现QPSK信号的数字调制解调

因最近客户需求&#xff0c;用纯PL实现AD9361的数字信号调制解调&#xff0c;于是就把各种数字调制都在AD9361上都实现了一遍。 优点就是&#xff1a;既可以在zynq系列上配置9361&#xff0c;也可以在纯FPGA系列配置9361。并且理解起来比较简单&#xff01;&#xff01;&#…

推荐4款免费好用文本转语音工具

Edge文本转语音 Edge文本转语音功能主要通过Edge-TTS实现。Edge-TTS是由微软开发的文本转语音&#xff08;TTS&#xff09;Python库&#xff0c;利用微软Azure Cognitive Services的强大功能&#xff0c;能够将文本信息转换成流畅自然的语音输出。该库支持多种中文语音语色&…

PID控制与模糊PID控制的比较

一、PID控制器的设计 1.PID控制原理图&#xff1a; PID控制其结构框图如下图所示&#xff1a; 图1&#xff1a;PID控制器结构框图 2.PID控制器传递函数的一般表达式 PID控制器传递函数的一般表达形式为&#xff1a; 其中kp为比例增益&#xff1b;ki为积分增益&#xff1b;k…

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

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

【YOLO8系列】(二)YOLOv8环境配置,手把手嘴对嘴保姆教学

目录 一. 准备环境 1.Anaconda下载 2.创建yolov8虚拟环境 3.pytorch安装 4.CUDA下载 5.CUDNN下载 二、yolov8模型下载 1.clone模型 2.pycharm配置 ①解释器配置 ②终端配置 3.安装必要库 4.下载训练模型 三、 环境验证 四、总结 YOLOv8 是 YOLO 系列最新的目标…

兼容性报错--调整字符集解决

文章目录 错误解决办法Unicode 字符集(两个字节来表示一个字符)多字节字符集(一个字节来表示一个字符)如何选择字符集char与wchar_t的区别LPCSTR与LPCWSTR的区别 错误 解决办法 切换字符集类型 Unicode 字符集(两个字节来表示一个字符) 优点&#xff1a; 支持更多的字符集…

Linux|背景 环境搭建

目录 一、简述Linux发展史 1.1计算机的诞生 1.2操作系统的诞生 1.3Linux操作系统开源 1.4Linux发行版本 二、搭建Linux环境 三、使用shell远程登入到Linux 一、简述Linux发展史 可能大家未听说过Linux&#xff0c;或者只知道它是一个搭配在计算机上的操作系统&#xff0…

Studio One直播声音怎么调 Studio One直播没有声音输出怎么办 studio one如何设置声音变好听

Studio One做为新生代音乐工作站&#xff0c;凭借更低的价格和完备的功能&#xff0c;获得了音乐人和直播行业工作者的青睐&#xff0c;尤其是对硬件声卡的适配支持更好&#xff0c;特别适合用来配合线上教学和电商带货。 一、Studio One直播声音怎么调 在Studio One进行直播时…

C基础day7

一、思维导图 二、课后练习 1、提示并输入一个字符串&#xff0c;统计该字符串中字母、数字、空格以及其他字符的个数 #include<myhead.h> #define M 20 int main(int argc, const char *argv[]) {int sum_a0,sum_b0,sum_c0,sum_d0;char str[M];printf("please en…

鼠标点击触发-----以控制开灯、宝箱触发为例

开灯 当点击时触发开灯效果 &#xff08;不用设置触发器&#xff09; using System.Collections; using System.Collections.Generic; using UnityEngine;public class OpenLight : MonoBehaviour {public Transform light;bool isOpen;private void OnMouseDown(){if (!isOpe…