Java字符串处理类

Posted by Wh0ami-hy on January 14, 2024

1. String类

字符串常量是用双引号括起的字符序列

字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节

// sss是字符串常量,而str是String类对象
String str = "sss";

String类实现了接口Serializable,意味着String对象可以串行化,支持在网络中传输

String类实现了接口Comparable,意味着String对象可以比较

String类是final类,不能被其他类继承

String类有属性private final char value[]; 用于存放字符串内容,并且该value是final类型,不能修改(是value不能指向新的地址而不是value的值不能修改)

1.1. String常用构造方法

方法名 说明
public String() 创建一个空白字符串对象
public String(char[] chs) 根据字符数组的内容,来创建字符串对象
public String(byte[] bys) 根据字节数组的内容,来创建字符串对象

1.2. String对象的创建

直接赋值

String s2 = "123";

先从常量池查看是否有"123"数据空间,如果有,直接指向。如果没有则重新创建,然后指向。s2最终指向的是常量池的空间地址

graph LR
A[栈, s2指向0x99] --> B[常量池, 值123,地址0x99];

调用构造器

String s2 = new String("123");

先在堆中创建空间,里面维护了value属性,指向常量池的"123"空间。如果常量池没有"123",重新创建。如果有,直接通过value指向。最终指向的是堆中的空间地址。

graph LR
A[栈, s2指向0x11] --> B[堆, value指向0x99,地址0x11];
B --> C[常量池, 值123, 地址0x99];

1.3. 字符串的特点

字符串对象一旦被分配,其内容不可变

String s = "123";
s = "456";

上面语句创建了两个对象,s对象发生了改变

graph LR
A[栈, s] --> |先指向| B[池, 123]
A --> |后指向|D[池, 456]

重要规则:常量相加,看的是池。变量相加,是在堆中

一共有几个对象:1个

String c = "123" + "456"; 

编译器会做一个优化,判断创建的常量池对象是否有引用指向 String a = "hello" +"abc" 等价于 String a = "helloabc"

一共有几个对象:3个

String a = "123";
String b = "456";
String c = a + b; 

1.4. String类的常见方法

用的时候查手册就行

方法名 说明
public boolean equals(Object anObject) 比较字符串的内容,严格区分大小写
public char charAt(int index) 返回字符串指定索引处的值
public int length() 返回此字符串的长度

2. StringBuffer类

StringBuffer代表可变的字符序列,可以通过某些方法调用来更改序列的长度和内容

StringBuffer是个容器

StringBuffer的直接父类是AbstractStringBuilder

StringBuffer实现了SerializabLe,即StringBuffer的对象可以串行化

在父类中AbstractStringBuilder有属性char[ ] value,不是final,该value 数组存放字符串的内容,因此是存放在堆中的

StringBuffer是一个final类, 不能被继承

String VS StringBuffer

String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率较低,核心原因:private final char value[]

StringBuffer保存的是字符串变量,里面的值可以更改,每次StringBuffer的更新实际上可以更新内容,不用每次更新地址,效率较高,核心原因:char[] value

StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的

2.1. 构造方法

方法名 功能
public StringBuffer() 构造一个没有字符的字符串缓冲区,初始容量为16个字符
public StringBuffer(String str) 构造一个初始化为指定字符串内容的字符串缓冲区。字符串缓冲区的初始容量为16加上字符串参数的长度

2.2. String与StringBuffer互转

2.2.1. String转StringBuffer

方式1 使用构造器

str = "";
StringBuffer stringBuffer = new StringBuffer(str);

方式2 使用的是append方法

str = "";
StringBuffer stringBuffer1 = new StringBuffer();
stringBuffer1 = stringBuffer1.append(str);

2.2.2. StringBuffer转String

方式1 使用StringBuffer提供的 toString方法

StringBuffer stringBuffer3 = new StringBuffer("123");
String s = stringBuffer3.toString();

方式2 使用构造器来搞定

StringBuffer stringBuffer3 = new StringBuffer("123");
String s = new String(stringBuffer3);

2.3. StringBuffer常见方法

方法名 说明
append
delete(start,end) 删,将start到end间的内容删除掉,不含end
replace(start,end,string) 改,将start到end间的内容替换掉,不含end
indexOf 查,查找子串在字符串第1次出现的索引,如果找不到返回-1
insert
length 获取长度(字符数)
String str = null;
StringBuffer sb = new StringBuffer();  
sb.append(str);  
System.out.println(sb);

最后输出的是null(字符串)

3. StringBuilder类

一个可变的字符序列。此类提供一个与StringBuffer兼容的API,但不保证同步。此类被设计用作StringBuffer的简易替换,用在字符串缓冲区被单个线程使用的地方。 在可能的情况下,建议使用这个类别优先于StringBuffer ,因为它在大多数实现中将更快

在StringBuilder 上的主要操作是append和insert方法,可重载这些方法,以接受任意类型的数据

StringBuilder继承AbstractStringBuilder类

StringBuilder实现了Serializable,说明StringBuilder对象是可以串行化的

StringBuilder是final类,不能被继承

StringBuilder对象字符序列仍然是存放在其父类 AbstractStringBuilder的 char[] value,因此,字符序列在堆中

StringBuilder的方法,没有做互斥的处理,即没有synchronized关键字,因此仅可在单线程的情况下使用StringBuilder

StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的

StringBuilder的方法使用和StringBuffer一样

4. 总结

  • 如果字符串存在大量的修改操作,一般使用StringBuffer 或StringBuilder
  • 如果字符串存在大量的修改操作,并在单线程的情况,使用StringBuilder
  • 如果字符串存在大量的修改操作,并在多线程的情况,使用StringBuffer
  • 如果我们字符串很少修改,被多个对象引用,使用String,比如配置信息等

本站总访问量