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

news2024/11/16 11:37:20

文章目录

  • 一、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 来进行字符串拼接,以避免频繁创建临时对象和提高性能。

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

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

相关文章

Java如何自定义注解及在SpringBoot中的应用

注解 注解&#xff08;Annotation&#xff09;&#xff0c;也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性&#xff0c;与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面&#xff0c;用来对这些元素进行说…

最快视频转绘-AnimateDiff-Lightning

最快视频转绘-AnimateDiff-Lightning Video-to-Video Generation AnimateDiff-Lightning 非常适合视频到视频的生成。使用 ControlNet 提供最简单的 comfyui 工作流程。 「ComfyUI-aki-v1.3.7z」链接&#xff1a;https://pan.quark.cn/s/199a753292d8 下载导入工作流 animat…

182440-00SF 同轴连接器

型号简介 182440-00SF是Southwest Microwave的一款连接器。该连接器采用 BeCu UNqS C17300 材料&#xff0c;并进行了镀金处理&#xff0c;以确保良好的导电性和耐腐蚀性&#xff1b;螺纹采用符合 ASTM A2582 标准的钢制合金&#xff0c;并进行磷酸盐钝化处理&#xff0c;以提高…

FunAudioLLM SenseVoice语音转录与CosyVoice语音合成及语音克隆使用案例

参考: https://fun-audio-llm.github.io/ 1、SenseVoice语音转录 在线体验:https://modelscope.cn/studios/iic/CosyVoice-300M 参考:https://github.com/FunAudioLLM/SenseVoice 下载: pip install -U funasr使用: from funasr import AutoModelmodel_dir = "…

如何从 Vue 2 无痛升级到 Vue 3,一文搞定!

大家好,我是CodeQi! 一位热衷于技术分享的码仔。 随着 Vue 3 的发布,许多开发者都面临着从 Vue 2 升级到 Vue 3 的挑战。 本文将详细介绍如何从 Vue 2 无痛升级到 Vue 3,包括每个步骤的详细说明与代码示例。 让我们开始吧! 准备工作 在正式开始升级之前,请确保你已经…

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

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

【Linux】网络新兵连

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 引言 在上一篇博客中&#xff0c;我们简单的介绍了一些Linux网络一些比较基本的概念。本篇博客我们将开始正式学习Linux网络套接字的内容&#xff0c;那么我们开始吧&#xff01; 1.网络中的地址管理 大家一…

【Linux】多线程_2

文章目录 九、多线程2. 线程的控制 未完待续 九、多线程 2. 线程的控制 主线程退出 等同于 进程退出 等同于 所有线程都退出。为了避免主线程退出&#xff0c;但是新线程并没有执行完自己的任务的问题&#xff0c;主线程同样要跟进程一样等待新线程返回。 pthread_join 函数…

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

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

【动态规划Ⅴ】二维数组的动态规划——0/1矩阵、最大正方形

二维数组的动态规划——0/1矩阵、最大正方形 最大正方形1277. 统计全为 1 的正方形子矩阵221. 最大正方形 01矩阵542. 01 矩阵 最大正方形 下面两个题目是非常相似的&#xff0c;只是一个统计正方形数目&#xff0c;一个统计最大正方形的面积。 1277. 统计全为 1 的正方形子矩…

【优先级队列PriorityQueue】

目录 1&#xff0c;优先级队列 1.1 概念 2&#xff0c;优先级队列的模拟实现 2.1 堆的概念 2.2 堆的存储方式 2.3 堆的创建 2.3.1 堆的向下调整&#xff08;大根堆&#xff09; 2.3.2 建堆的时间复杂度​编辑 2.4 堆的插入与删除 2.4.1 堆的插入 2.4.2 堆的删除 3&a…

源码编译构建LAMP(企业网站架构部署与优化)

部署LAMP平台 LAMV架构是目前成熟的企业网站应用模式之一&#xff0c;指的是协同工作的一整套系统和相关软件&#xff0c;能够提供动态Web站点服务及其应用开发环境。LAMP是一个缩写词&#xff0c;具体包 括 Linux操作系统&#xff0c;Apache网站服务器、MySQL数据库服务器、P…

ElementPlusError: [ElPagination] 你使用了一些已被废弃的用法,请参考 el-pagination 的官方文档 - 报警告之一

一、问题描述&#xff1a; 今天在使用elementui plus的时候遇到了一个奇葩的问题&#xff0c; 就是提示 使用了一些已被废弃的用法&#xff0c; 奇葩就在于我是 复制另一个页面的分页&#xff0c; 一摸一样的东西&#xff0c;就只这个页面报错&#xff0c; 分页也不出 为了这个…

App Cleaner Uninstaller 8.3.0激活版 最佳卸载程序和清理助手

App Cleaner & Uninstaller 完全安全地删除 Mac 上的程序&#xff0c;删除应用程序的残留物&#xff0c;管理扩展程序和启动程序。 App Cleaner & Uninstaller 8.3.0激活版下载 卸载应用程序和所有不需要的垃圾文件 当您将应用程序拖放到废纸篓时&#xff0c;请检查您…

鸿蒙开发学习笔记1

一、下载 deveco-studio 编译器 https://developer.huawei.com/consumer/cn/deveco-studio/#download 二、ArkTs 0、基本数据类型&#xff1a; 3种&#xff1a;string、number、boolean 1、存储数据&#xff08;变量、常量&#xff09; 注&#xff1a;类似于 ts 使用 con…

【work】AI八股-神经网络相关

Deep-Learning-Interview-Book/docs/深度学习.md at master amusi/Deep-Learning-Interview-Book GitHub 网上相关总结&#xff1a; 小菜鸡写一写基础深度学习的问题&#xff08;复制大佬的&#xff0c;自己复习用&#xff09; - 知乎 (zhihu.com) CV面试问题准备持续更新贴 …

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

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

什么,有狗快跑!慢着,这次手把手教你怎么过安全狗!(sql注入篇)

前言 在记忆里上次绕安全狗还是在上次&#xff0c;开开心心把自己之前绕过狗的payload拿出来&#xff0c;发现全部被拦截了&#xff0c;事情一下子就严肃起来了&#xff0c;这就开整。 环境 本次环境如下sqli-lab的sql注入靶场 网站安全狗APACHE版V4.0版本的最高防护等级绕过…

北京大学长安汽车发布毫米波与相机融合模型RCBEVDet:最快能达到每秒28帧

Abstract 三维目标检测是自动驾驶中的关键任务之一。为了在实际应用中降低成本&#xff0c;提出了利用低成本的多视角相机进行3D目标检测&#xff0c;以取代昂贵的LiDAR传感器。然而&#xff0c;仅依靠相机很难实现高精度和鲁棒性的3D目标检测。解决这一问题的有效方法是将多视…

思维+数学,CF 1138B - Circus

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 1138B - Circus 二、解题报告 1、思路分析 设第一组会小丑和杂技的人数分别为x1, y1 第二组会小丑和杂技的人数分别为x2, y2 显然根据要求有&#xff1a; x1 y2 > x1 x2 x2 y2 上式说明第二组每…