Java字符串(String)详解

一、字符串概述

在Java中只要是双引号""引起来的就是字符串,字符串是Java.lang.String类的实例,用于表示一系列字符序列。字符串是不可变的,这意味着字符串一旦创建,就不能更改字符串的内容。

字符串的操作:拼接、比较、替换、截取、查找、切割、检索、加密、打乱顺序、大小写转换....操作

本文章主要包括的内容有:

1、String、StringBuilder、StringJonier、Pattern、Matcher等字符串常见操作

2、实际开发中的案例

3、字符串相关的底层原理

二、String

1、创建字符串的两种方式

1、直接赋值

String name = "张三";

2、new

构造方法说明 
public String()创建空白字符串,不包含任何内容
public String(String original)根据传入的字符串,创建字符串对象
public String(char[] chs)根据字符数组,创建字符串对象
public String(byte[] chs)根据字节数组,创建字符串对象
public static void main(String[] args) {
        //1、直接赋值
        String s1 = "abc";
        System.out.println(s1);
        //2、使用new的方式来获取一个字符串对象(不使用)
        String s2 = new String();
        System.out.println(s2);
        //3、传递一个字符串,根据传递的字符串内容再创建一个新的 字符串对象(不使用)
        String s3 = new String("abc");
        System.out.println(s3);
        //4、传递一个字符数组,根据字符数组的内容创建一个新的字符串
        //对于这个操作是有应用场景的
        //例如:修改字符串的内容、abc -> Qbc
        //我们可以将abc先转换成字符数组,然后根据索引修改里面的值
        char[] chs = {'a', 'b', 'c', 'd'};
        String s4 = new String(chs);
        System.out.println(s4);
        //5、传递一个字节数组,根据字节数组的内容创建一个新的字符串对象
        //应用场景:以后在网络中传输的数据其实是字节信息
        //我们一般要把字节信息进行转换,转成字符串,此时就要用到这个构造了
        byte[] bytes = {97, 98, 99};
        String s5 = new String(bytes);
        System.out.println(s5);
    }

2、字符串在内存的表现形式

这里会涉及到Java中三块内存分别是:栈内存、堆内存、方法区、字符串常量池

栈:方法运行的时候进栈,执行完出栈

堆:new出来的对象都在这里

方法区:类加载的时候、class文件会临时存储在这里

串池:字符串常量池,直接赋值的字符串才会在这个里面,new出来的不在这个里面((JDK7以前串池是在方法区中的,7以后该成在堆内存中了))

例1(直接赋值字符串内存图):

public class StringDemo{
    public static void main(String[] args){
        String s1 = "abc";
        String s2 = "abc";
    }
}

程序运行,首先main方法加载入栈,然后从main方法里面,从上往下执行代码

第一行代码是等号直接赋值的,在main方法中首先会创建一个变量s1,等号的右边,系统首先会看串池中有没有abc,第一次加载是没有的,在串池中就会创建abc,然后把地址赋值给main方法中的s1变量。

执行第二行代码时,由于串池中现在已经有abc了,它现在就不会去创建一个新的,而是会复用串池中abc,将abc的地址值赋值给s2

例2(通过new创建字符串的内存图)

public class StringTest{

    public static void main(String[] args){
        char[] chs = {'a','b','c'};
        String s1 = new String(chs);
        String s2 = new String(chs);
    }
}

首先程序运行,main方法入栈,运行第一行创建字符数组,堆内存中创建变量chs保存在堆内存中开辟空间存储的字符数组内存地址。

第二行代码,此时等号的右边是new出来的,等号左边是一个变量s1存储在栈中,右边在堆内存中开辟一个空间,存储abc值,并将地址值赋值给变量s1

第三行代码,由于是new创建的,我们知道new一次就会开辟一次空间,所以就会创建一个新的空间再次存储abc,并将地址值赋值给s2

这里我们可以知道,s1、s2记录的地址值不一样,这种方式创建的字符串不会复用,如果创建过多,会浪费系统空间。

3、字符串常用方法

Java中的String类提供了许多用于处理字符串的常用方法。以下是一些最常用的方法:

length() - 返回字符串的长度。

String str = "Hello";
int len = str.length(); // 结果为5

charAt(int index) - 返回指定索引处的字符。

String str = "Hello";
char ch = str.charAt(1); // 结果为'e'

concat(String str) - 连接两个字符串。

String str1 = "Hello";
String str2 = "World";
String str3 = str1.concat(str2); // 结果为"HelloWorld"

equals(Object obj) - 比较两个字符串的内容是否相同。

String str1 = "Hello";
String str2 = "Hello";
boolean isEqual = str1.equals(str2); // 结果为true

equalsIgnoreCase(String anotherString) - 比较两个字符串,忽略大小写。

String str1 = "Hello";
String str2 = "hElLo";
boolean isEqual = str1.equalsIgnoreCase(str2); // 结果为true

startsWith(String prefix) - 测试字符串是否以指定的前缀开始。

String str = "HelloWorld";
boolean isStart = str.startsWith("Hello"); // 结果为true

endsWith(String suffix) - 测试字符串是否以指定的后缀结束。

String str = "HelloWorld";
boolean isEnd = str.endsWith("World"); // 结果为true

indexOf(int ch) 和 indexOf(String str) - 返回指定字符或子字符串第一次出现的索引。

String str = "HelloWorld";
int index = str.indexOf('W'); // 结果为5
int indexStr = str.indexOf("World"); // 结果为5

lastIndexOf(int ch) 和 lastIndexOf(String str) - 返回指定字符或子字符串最后一次出现的索引。

String str = "HelloWorldHello";
int lastIndex = str.lastIndexOf('l'); // 结果为11
int lastIndexStr = str.lastIndexOf("Hello"); // 结果为10

substring(int beginIndex) 和 substring(int beginIndex, int endIndex) - 返回字符串的子字符串。

String str = "HelloWorld";
String subStr1 = str.substring(6); // 结果为"World"
String subStr2 = str.substring(0, 5); // 结果为"Hello"

trim() - 去除字符串两端的空白字符。

String str = " Hello ";
String trimmedStr = str.trim(); // 结果为"Hello"

replace(char oldChar, char newChar) 和 replace(CharSequence target, CharSequence replacement) - 替换字符串中的字符或子字符串。

String str = "Hello World";
String replacedStr1 = str.replace('o', 'a'); // 结果为"Hella Warld"
String replacedStr2 = str.replace("World", "Java"); // 结果为"Hello Java"

toLowerCase() 和 toUpperCase() - 将字符串转换为小写或大写。

String str = "Hello";
String lowerCaseStr = str.toLowerCase(); // 结果为"hello"
String upperCaseStr = str.toUpperCase(); // 结果为"HELLO"

这些只是String类提供的一些常用方法,实际上它还有更多的方法可以用于处理字符串,可以去Api文档查看。

三、StringBuilder

StringBuilder 是 Java 中一个可变的字符序列,用于构造字符串,尤其是在需要频繁修改字符串的场景下。StringBuilder 内部实现了一个可变的字符数组,通过数组索引来操作字符,因此比使用 String 连接字符串的效率要高得多。

特性

  1. 可变StringBuilder 可以在创建后修改其内容。
  2. 线程不安全:在多线程环境下,StringBuilder 的操作可能不安全,因为多个线程可能同时修改其内部状态。如果需要在多线程环境下操作,可以使用 StringBuffer,它是 StringBuilder 的线程安全版本。
  3. 效率高:相比于使用 String 进行字符串连接,StringBuilder 的效率更高,因为它减少了内存分配和垃圾收集的开销。

常用方法

  1. 构造方法

    • StringBuilder(): 构造一个空的 StringBuilder
    • StringBuilder(int initialCapacity): 构造一个具有指定初始容量的 StringBuilder
    • StringBuilder(String str): 构造一个包含指定字符串内容的 StringBuilder
  2. 添加和插入

    • append(String str): 追加指定字符串到此字符序列。
    • append(char c): 追加指定字符到此字符序列。
    • append(int i): 追加指定整数到此字符序列,将其转换为字符串。
    • append(boolean b): 追加指定的布尔值到此字符序列,将其转换为字符串。
    • append(char[] str, int offset, int len): 追加指定字符数组的子序列到此字符序列。
    • insert(int offset, String str): 在此字符序列的指定位置插入指定的字符串。
    • ...(还有更多重载的 append 和 insert 方法)
  3. 删除和替换

    • delete(int start, int end): 移除此序列的子字符串中的字符。
    • deleteCharAt(int index): 移除此序列指定位置的字符。
    • replace(int start, int end, String str): 使用给定字符串替换此序列的子字符串。
  4. 获取字符和子字符串

    • charAt(int index): 返回此序列中指定位置的字符。
    • substring(int start, int end): 返回一个新的字符序列,它是此序列的一个子序列。
  5. 容量和长度

    • length(): 返回此字符序列的长度。
    • capacity(): 返回当前容量。
    • ensureCapacity(int minimumCapacity): 确保容量至少等于指定的最小值。
  6. 其他

    • reverse(): 反转此字符序列。
    • setCharAt(int index, char ch): 将此序列中指定位置的字符设置为指定的字符。
    • toString(): 返回此字符序列的字符串表示形式。

使用示例

public class StringBuilderExample {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
// 追加字符串
sb.append("Hello");
sb.append(" ");
sb.append("World");
// 插入字符串
sb.insert(5, "Beautiful");
// 删除字符
sb.deleteCharAt(6);
// 替换子字符串
sb.replace(11, 16, "Java");
// 获取子字符串
String subStr = sb.substring(0, 5);
// 输出结果
System.out.println(sb.toString()); // 输出: Hello Beautiful Java
System.out.println(subStr); // 输出: Hello
}
}

在实际编程中,根据具体需求选择合适的 StringBuilder 方法,可以高效地构建和修改字符串。

四、StringJoiner

StringJoiner 是 Java 8 引入的一个实用类,它允许你以特定的分隔符、前缀和后缀来连接多个字符串。StringJoiner 特别适用于需要拼接多个字符串,并且希望这些字符串之间有特定的分隔符,或者在整体字符串的开始和结束处有特定前缀和后缀的情况。

特性

  1. 灵活性:你可以为 StringJoiner 指定分隔符、前缀和后缀。
  2. 线程安全StringJoiner 的实例是线程安全的,多个线程可以同时使用同一个 StringJoiner 实例,而不需要额外的同步。
  3. 高效StringJoiner 内部使用 StringBuilder 来存储和构建字符串,因此它在性能上表现良好。

常用方法

  1. 构造方法

    • StringJoiner(CharSequence delimiter): 创建一个新的 StringJoiner,使用指定的分隔符。
    • StringJoiner(CharSequence delimiter, CharSequence prefix, CharSequence suffix): 创建一个新的 StringJoiner,使用指定的分隔符、前缀和后缀。
  2. 添加字符串

    • add(CharSequence newElement): 添加一个新的字符串元素。
    • merge(CharSequence delimiter, CharSequence newElement): 如果 newElement 不为空,则将其添加到当前构建器中,前面添加指定的分隔符。这通常用于在连接多个字符串时,合并重复的分隔符。
  3. 获取结果字符串

    • toString(): 返回由分隔符连接的字符串,包括前缀和后缀。
  4. 设置空值策略

    • setEmptyValue(CharSequence emptyValue): 设置当没有元素时返回的字符串。默认情况下,如果没有元素,toString() 方法将返回空字符串(包括前缀和后缀)。

使用示例

public class StringJoinerExample {
public static void main(String[] args) {
// 使用逗号作为分隔符
StringJoiner joiner = new StringJoiner(",");
// 添加元素
joiner.add("apple");
joiner.add("banana");
joiner.add("cherry");
// 合并重复的分隔符
joiner.merge(",", "banana"); // 这不会改变结果,因为 "banana" 已经存在
// 获取结果字符串
String result = joiner.toString(); // 输出: apple,banana,cherry
System.out.println(result);
// 使用前缀和后缀
StringJoiner joinerWithPrefixSuffix = new StringJoiner(", ", "[", "]");
joinerWithPrefixSuffix.add("one");
joinerWithPrefixSuffix.add("two");
String resultWithPrefixSuffix = joinerWithPrefixSuffix.toString(); // 输出: [one, two]
System.out.println(resultWithPrefixSuffix);
// 设置空值策略
StringJoiner emptyJoiner = new StringJoiner(",");
emptyJoiner.setEmptyValue("no elements");
String emptyResult = emptyJoiner.toString(); // 输出: no elements
System.out.println(emptyResult);
}
}

在上面的示例中,我们展示了如何使用 StringJoiner 来连接字符串,并设置不同的分隔符、前缀、后缀以及空值策略。通过合理地使用 StringJoiner,你可以简化字符串拼接的逻辑,并提高代码的可读性和维护性。

五、Pattern、Matcher

在Java中,Pattern类是用来表示正则表达式的编译表示形式。正则表达式是一种强大的文本处理工具,可以用来匹配、查找和替换文本中的特定字符序列。Pattern类的主要作用是将正则表达式(指定为字符串)编译为此类的实例,然后这个实例可以被用来创建一个Matcher对象,该对象可以用于匹配任意字符序列针对正则表达式。

Pattern类的主要方法包括:

  1. compile(String regex):该方法用于将给定的正则表达式编译并返回一个Pattern对象。这是使用正则表达式的第一步。
  2. matcher(CharSequence input):该方法用于创建一个匹配器,该匹配器将使用此模式的规则对输入序列进行匹配。
  3. pattern():返回此模式的字符串表示形式,也就是编译此模式的正则表达式。
  4. flags():返回此模式的匹配标志。
  5. toString():返回此模式的字符串表示形式,该字符串是正则表达式的字面值表示。
  6. quote(String s):返回指定字符串的字面值模式String。此方法产生一个字符串,可以安全地用于匹配字符串中的文字(而不是解释为正则表达式的其他元素)。

Pattern类通常与Matcher类一起使用,Matcher类包含了一些用于执行匹配操作的方法,如find()matches()replaceFirst()replaceAll()等。例如,你可以使用find()方法在输入字符串中找到所有与正则表达式匹配的部分。

需要注意的是,虽然Pattern类和Matcher类提供了强大的文本处理能力,但在使用正则表达式时也需要谨慎,因为复杂的正则表达式可能会导致性能问题,或者在某些情况下可能无法正确匹配预期的结果。因此,在设计正则表达式时,应尽量保持其简单明了,并尽可能进行充分的测试以确保其正确性。

import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PatternMatcherExample {
public static void main(String[] args) {
// 定义一个包含电子邮件地址的字符串
String emailText = "Contact us at info@example.com or support@example.org for assistance.";
// 编译一个用于匹配电子邮件地址的正则表达式
Pattern pattern = Pattern.compile("\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b");
// 创建一个Matcher对象来应用模式
Matcher matcher = pattern.matcher(emailText);
// 使用find()方法查找匹配项
while (matcher.find()) {
// 输出匹配到的电子邮件地址
System.out.println("Found email: " + matcher.group());
}
}
}

在这个例子中,我们定义了一个包含两个电子邮件地址的字符串emailText。然后,我们使用Pattern.compile()方法编译了一个正则表达式,该表达式用于匹配电子邮件地址的通用格式。

接下来,我们使用pattern.matcher(emailText)创建了一个Matcher对象,并将要搜索的文本传递给它。

最后,我们使用matcher.find()方法在文本中查找与正则表达式匹配的子序列。当找到匹配项时,find()方法返回true,并且我们可以使用matcher.group()方法获取匹配的文本。这个过程在while循环中重复进行,直到没有更多的匹配项为止。

注意,正则表达式"\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b"用于匹配大多数简单的电子邮件地址。这个正则表达式并不是完美的,因为它可能不会匹配所有有效的电子邮件地址格式,但它对于大多数常见的情况应该足够了。对于更复杂的电子邮件地址验证,可能需要使用更复杂的正则表达式或专门的电子邮件验证库。

  • 9
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱摸鱼的呆瓜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值