字符串广泛应用 在Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。String 类是不可改变的,所以你一旦创建了 String 对象,那它的值就无法改变了,所以这一决为“一成不变”。
创建字符串
创建字符串的最简单方式:
String str = "LoveCTO";
此外,和其它对象一样,可以使用关键字“new”和构造方法来创建String对象:
String str = new String("LoveCTO");
除了这个构造方法外,jdk8中共计提供了16个String的构造方法。
String的核心
String类的核心是其内部的两个成员变量(final修饰的value字符数组和hash):
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
String的一成不变的根源在于value字符数组是final的。hash的计算方式如下(String重写了Object的hashCode方法,使用31哈希算法):
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
比较两个字符串是否相同,使用String重写的equals方法:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
先比较两个字符串对象是否是同一个,再比较是否都是String对象,再看字符串长度是否相同,最后再逐个字符比较。
String常用方法
下面列举几个常用的String类的方法:
//是否以某个字符串作为前缀
public boolean startsWith(String prefix);
//是否以某个字符串作为后缀
public boolean endsWith(String suffix);
//查找子字符串的位置,未查找到返回-1
public int indexOf(String str);
//字符串截取
public String substring(int beginIndex);
//字符串范围截取
public String substring(int beginIndex, int endIndex);
//字符串中是否包含字符序列s
public boolean contains(CharSequence s);
//字符串子串替换
public String replace(CharSequence target, CharSequence replacement);
//告知此字符串是否匹配给定的正则表达式
public boolean matches(String regex);
//使用指定的格式字符串和参数返回一个格式化字符串
public static String format(String format, Object... args);
//使用给定的replacement替换此字符串所有匹配给定的正则表达式的子字符串
public String replaceAll(String regex, String replacement);
//使用给定的replacement替换此字符串匹配给定的正则表达式的第一个子字符串
public String replaceFirst(String regex, String replacement);
//将指定字符串连接到此字符串的结尾
public String concat(String str);
//根据给定正则表达式的匹配拆分此字符串
public String[] split(String regex);
更多可参考 JAVA String API 8 英文,JAVA String API 6 中文。
字符串拼接大比拼
- 直接用“+”号
- 使用String的方法concat
- 使用StringBuilder的append
- 使用StringBuffer的append
- 使用String.join(JAVA8)
- 使用String.format
- 使用StringJoiner(JAVA8)
上面4种拼接方式性能对比:
- 无论如何直接用“+”号连接字符串都是最慢的
- 在拼接少数字符串(不超过4个)的时候,concat效率是最高的
- 多个字符串拼接的时候,StringBuilder/StringBuffer的效率是碾压的
- 在不需要考虑线程安全问题的时候,使用StringBuilder的效率比StringBuffer更高
- String.join内部使用的是StringJoiner,效率优于“+”和concat,代码更简洁
- String.format内部基于StringBuilder,效率优于“+”和concat,类似C语言
- StringJoiner内部原理是StringBuilder,java8新特性,可使代码更加简洁
字符串拆分/字符串分割大比拼
- String的split
- StringTokenizer
StringTokener.hasMoreElement和String.split(String.split是用正则表达式匹配,所以不使用KMP字符串匹配算法)用的都是按顺序遍历的算法,时间复杂度O(m*n),较高。
不过StringTokener是一边按顺序遍历,一边返回每个分组;而Spring.split是全部分组完成,再返回字符串数组。这个区别不大,但是如果我们不需要全部都分组,只需要某个分组的字符串,那么StringTokener性能会好点。