Java中String相关知识
一、字符串基本知识
1.String对象的创建
直接创建一个常量String对象,结果如下:
创建常量字符串和创建字符串对象的区别,如下图:
实际上,字符串常量存储在字符串常量池,目的是为了共享;而字符串非常量对象存储在堆中。
s1和s2都是常量字符串,用等号比较直接比的都是值。
s3和s4都是字符串对象,即使它们的值相等,但是地址不一样,所以等号为false
2.字符串的特性
常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
只要其中一个是变量,结果就在堆中。
如果拼接的结果调用intern方法,返回值就在常量池中。
3.字符串相关方法
方法 | 说明 |
---|---|
char charAt(int index) | 返回某索引处的字符return value[index] |
boolean isEmpty() | 判断是否是空字符串:return value.length == 0 |
String toLowerCase() | 将 String 中的所有字符转换为小写 |
String toUpperCase() | 将 String 中的所有字符转换为大写 |
String trim() | 返回字符串的副本,忽略前导空白和尾部空白 |
int compareTo(String anotherString) | 比较两个字符串的大小 |
String substring(int beginIndex) | 返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串 |
String substring(int beginIndex, int endIndex) | 返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串 |
boolean endsWith(String suffix) | 测试此字符串是否以指定的后缀结束 |
boolean startsWith(String prefix) | 测试此字符串是否以指定的前缀开始 |
boolean startsWith(String prefix, int toffset) | 测试此字符串从指定索引开始的子字符串是否以指定前缀开始 |
int indexOf(String str) | 返回指定子字符串在此字符串中第一次出现处的索引 |
int indexOf(String str, int fromIndex) | 返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始 |
int lastIndexOf(String str) | 返回指定子字符串在此字符串中最右边出现处的索引 |
int lastIndexOf(String str, int fromIndex) | 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索 |
String replace(char oldChar, char newChar) | 返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的 |
String replaceAll(String regex, String replacement) | 使 用 给 定 的replacement 替换此字符串所有匹配给定的正则表达式的子字符串 |
String replaceFirst(String regex, String replacement) | 使 用 给 定 的replacement 替换此字符串匹配给定的正则表达式的第一个子字符串 |
String[] split(String regex) | 根据给定正则表达式的匹配拆分此字符串 |
4.String与基本数据类型的转换
1)字符串转换为基本数据类型或包装类:
public static int parseInt(String s)
2)基本数据类型转换为字符串:
调用String类的public String valueOf(int n)
可将int型转换为字符串
3)字符数组转换为字符串:
String 类的构造器:String(char[]) 和 String(char[],int offset,int length)
,分别用字符数组中的全部字符和部分字符创建字符串对象。
4)字符串转换为字符数组:
public char[] toCharArray()
:将字符串中的全部字符存放在一个字符数组中的方法
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
:提供了将指定索引范围内的字符串存放到数组中的方法
5)字节数组转换为字符串:
String(byte[])
:通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String
6)字符串转换为字节数组:
public byte[] getBytes()
:使用平台的默认字符集将此 String 编码为byte 序列,并将结果存储到一个新的 byte 数组中
public byte[] getBytes(String charsetName)
:使用指定的字符集将 此 String 编码到 byte 序列,并将结果存储到新的 byte 数组
二、字符串相关的类
1.StringBuffer类
1.1 StringBuffer类介绍
java.lang.StringBuffer代表可变的字符序列,JDK1.0中声明,可以对字符串内容进行增删,此时不会产生新的对象
它的底层代码:
1.2 StringBuffer类创建
StringBuffer类必须用构造器生成,它有三个构造器:
构造器 | 说明 |
---|---|
StringBuffer() | 初始容量为16的字符串缓冲区 |
StringBuffer(int size) | 构造指定容量的字符串缓冲区 |
StringBuffer(String str) | 将内容初始化为指定字符串内容,此时容量为字符串长度+16 |
1.3 StringBuffer类常用方法
方法 | 说明 |
---|---|
StringBuffer append(xxx) | 用于进行字符串拼接 |
StringBuffer delete(int start,int end) | 删除指定位置的内容 |
StringBuffer replace(int start, int end, String str) | 把[start,end)位置替换为str |
StringBuffer insert(int offset, xxx) | 在指定位置插入xxx |
StringBuffer reverse() | 把当前字符序列逆转 |
在使用append和insert方法时,如果原来value数组长度不够,可以扩容
2.StringBuilder类
2.1 StringBuilder类介绍
StringBuilder和StringBuffer很相似,也是可变的字符序列,功能也一样。
3.String、StringBuffer和StringBuilder对比
String:不可变字符序列
StringBuffer:可变字符序列、效率低、线程安全(扩容方法中有关键字synchronized)
StringBuilder:可变字符序列、效率高、线程不安全(扩容方法没有关键字synchronized)
扩容问题:
如果要添加的数据底层数组存储不下了,就需要扩容底层的数组。
默认情况下,扩容为原来容量的2倍+2,同时将原有数组中的元素复制到新的数组中;如果容量还不够,直接选取需要的容量大小作为新的容量。
开发建议:
在需要多次修改字符串的情况下,String效率最低,不建议使用;建议使用StringBuffer(int capacity)或StringBuilder(int capacity)方法,考虑线程安全问题选取。
StringBuilder线程不安全原因:
StringBuilder里的成员变量:
// 存储的字符串(通常情况一部分为字符串内容,一部分为默认值)
char[] value;
// 数组已经使用数量
int count;
StringBuilder中的方法是没有synchronized这个关键字的,它的append方法中的count+=len
导致了线程不安全,当多个线程都要使用append进行添加字符串时,count会增加,如果被同时读取到一个值,那么改变后的结果就不正确了:
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
在后面调用getChars时,因为count不正确,所以可能发生越界异常的情况。