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://xiahunao.cn/news/3224010.html

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

相关文章

新手教学系列——crontab 使用不当引发的服务器性能问题

起因及症状 最近,我们的一台服务器随着运行时间的增加,逐渐出现了压力过大的问题。具体表现为数据库连接数飙升至 4000+,Redis 频繁超时,系统报错文件打开数过多等。针对这些问题,我们逐一检查了数据库连接池、Redis 连接池以及系统的 ulimit 配置,但都未能找到问题的根…

服务注册Eureka

目录 一、背景 1、概念 2、CAP 理论 3、常见的注册中心 二、Eureka 三、搭建 Eureka Server 1、搭建注册中心 四、服务注册 五、服务发现 六、Eureka 和 Zooper 的区别 一、背景 1、概念 远程调用就类似于一种通信 例如&#xff1a;当游客与景区之间进行通信&…

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

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

如何借助社交媒体影响者的力量,让品牌影响力倍增?

一、引言&#xff1a;为何社交媒体影响者如此关键&#xff1f; 在信息爆炸的今天&#xff0c;社交媒体已成为塑造消费者行为与品牌认知的重要渠道。社交媒体影响者&#xff0c;凭借其在特定领域的专业知识、庞大的粉丝基础及高度的互动性&#xff0c;成为了品牌传播不可忽视的…

【鸿蒙学习笔记】属性学习迭代笔记

这里写目录标题 TextImageColumnRow Text Entry Component struct PracExample {build() {Row() {Text(文本描述).fontSize(40)// 字体大小.fontWeight(FontWeight.Bold)// 加粗.fontColor(Color.Blue)// 字体颜色.backgroundColor(Color.Red)// 背景颜色.width(50%)// 组件宽…

【LLM】三、open-webui+ollama搭建自己的聊天机器人

系列文章目录 往期文章回顾&#xff1a; 【LLM】二、python调用本地的ollama部署的大模型 【LLM】一、利用ollama本地部署大模型 目录 前言 一、open-webui是什么 二、安装 1.docker安装 2.源码安装 三、使用 四、问题汇总 总结 前言 前面的文章&#xff0c;我们已经…

【Python的pip配置、程序运行、生成exe文件】

Python的pip配置、程序运行、生成exe文件 一、安装Python 通过官网下载对应的版本&#xff0c;安装即可。 下载地址&#xff1a;https://www.python.org/downloads/ Python标准库查看&#xff08;Python自带库&#xff09; Python 标准库文档 安装Python的时候&#xff0c…

昇思25天学习打卡营第13天 | ShuffleNet图像分类

ShuffleNet网络介绍 ShuffleNetV1是旷视科技提出的一种计算高效的CNN模型&#xff0c;和MobileNet, SqueezeNet等一样主要应用在移动端&#xff0c;所以模型的设计目标就是利用有限的计算资源来达到最好的模型精度。ShuffleNetV1的设计核心是引入了两种操作&#xff1a;Pointw…

移除元素的讲解,看这篇就够了!

一&#xff1a;题目 博主本文将用指向来形象的表示下标位的移动。 二&#xff1a;思路 1&#xff1a;两个整形&#xff0c;一个start&#xff0c;一个end&#xff0c;在一开始都 0&#xff0c;即这里都指向第一个元素。 2&#xff1a;在查到val之前&#xff0c;查一个&…

01 | 基础架构:一条SQL查询语句是如何执行的?

此系列文章为极客时间课程《MySQL 实战 45 讲》的学习笔记&#xff01; 引言 在了解 SQL 查询语句如何执行之前&#xff0c;先了解下MySQL 的基本架构示意图。 MySQL 分为 Server 层和引擎层。 Server 层包括连接器、查询缓存、分析器、优化器、执行器等&#xff0c;涵盖 M…

逆向分析之电脑端如何调试一些只能手机端浏览器才可以打开的网站

手机端浏览器的指纹和电脑端浏览器的指纹是不同的,这样只在手机端浏览器运行的网站则可以检测网站是否满足手机端浏览器指纹的要求,不满足则可以进行一些反爬措施。 例如一些公众号,其实就是使用手机端浏览器打开的H5网站,就可以进行手机端浏览器指纹检测。 这里只是讲解下…

硬盘分区读不出来的危机与数据拯救指南

在数字时代&#xff0c;硬盘作为我们存储珍贵数据的“保险箱”&#xff0c;其稳定性和可访问性至关重要。然而&#xff0c;当硬盘分区突然读不出来时&#xff0c;这份安全感瞬间化为泡影&#xff0c;让人心急如焚。本文将深入探讨硬盘分区读不出来的原因、提供两种实用的数据恢…

可以添加todo清单桌面小组件的便签哪个好?

在我们快节奏的生活中&#xff0c;有效的时间管理和任务追踪是必不可少的。为了实现这一目标&#xff0c;许多人选择使用桌面便签&#xff0c;尤其是那些具有Todo清单桌面小组件的便签。但是&#xff0c;面对市场上众多选择&#xff0c;可以添加todo清单桌面小组件的便签哪个好…

springboot中@bean注解的创建和使用

bean的创建顺序 在Spring Boot中&#xff0c;当一个配置类&#xff08;使用Configuration注解的类&#xff09;中定义了多个bean时&#xff0c;这些bean的创建顺序并不完全由它们在类中的声明顺序决定。Spring框架在创建和管理bean时&#xff0c;遵循了复杂的依赖注入和生命周…

使用微pe装系统

本文仅作为记录&#xff0c;不作为教程。 今天心血来潮想下点游戏玩玩&#xff0c;一看之前分的200gc盘已经红了&#xff0c;再加上大学之后这个笔记本已经用得很少了&#xff0c;于是打算重装电脑。 参考: 微PE辅助安装_哔哩哔哩_bilibil… 1.下载微pe和win10系统到U盘 我这…

Day65 代码随想录打卡|回溯算法篇---组合总和II

题目&#xff08;leecode T40&#xff09;&#xff1a; 给定一个候选人编号的集合 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意&#xff1a;解集不能包含…

JAVA的String的不可变特性

在学习JAVA的时候&#xff0c;看到了JAVA的String具有不可变的特性&#xff0c;他是说&#xff0c;JAVA的String在创建好后&#xff0c;JVM将这个String变量指向内存中的一个地址&#xff0c;当下次改变这个String变量的时候&#xff0c;改变的不是这个变量的值&#xff0c;而是…

可转债之强赎条款

摘要&#xff1a;每天学习一点金融小知识 做可转债投资&#xff0c;强赎风险是特别需要注意的&#xff0c;若投资者没有及时采取措施&#xff0c;就有可能造成很大的损失。本文从可转债的定义、强赎条款的原因及强赎的情况几个方面来介绍下可转债的强赎条款。 什么是可转换债券…

如何评价Flutter?

哈喽&#xff0c;我是老刘 我们团队使用Flutter已经快6年了。 有很多人问过我们对Flutter的评价。 今天在这里回顾一下6年前选择Flutter时的原因&#xff0c;以及Flutter在这几年中的实际表现如何。 选择Flutter时的判断 1、性能 最开始吸引我们的就是其优秀的性能。 特别是…

imx6ull/linux应用编程学习(15) 移植MQTT客户端库

1. 准备开发环境 确保你的Ubuntu系统已经安装了必要的工具和依赖项。打开终端并运行以下命令&#xff1a; sudo apt update sudo apt install build-essential cmake git2. 获取MQTT库 git clone https://github.com/eclipse/paho.mqtt.c.git cd paho.mqtt.c3. 编译MQTT库 mk…