String类
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence{}
一旦一个String对象被创建,包含在这个对象中的字符序列是不可改变的,包括该类后续的所有方法都是不能修改该对象的,直至该对象被销毁,这是我们需要特别注意的(该类的一些方法看似改变了字符串,其实内部都是创建一个新的字符串)
成员变量
/**用来存储字符串 */
private final char value[];
/** 缓存字符串的哈希码 */
private int hash; // Default to 0
/** 实现序列化的标识 */
private static final long serialVersionUID = -6849794470754667710L;
一个 String 字符串实际上是一个 char 数组。
构造方法
String str1 = "abc";
String str2 = new String("abc");
String str3 = new String(new char[]{'a','b','c'});
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 类重写了equals方法,比较的是组成字符串的每一个字符是否相同,如果都相同则返回true,否则返回false
hashCode()
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;
}
这里有一个奇怪的数字31,网上查了一下,有以下两点原因:
第一,31是一个不大不小的质数,是作为hashCode乘子的优选质数之一。另外一下相近的质数,比如37、41、43等等,也都是不错的选择,那么为啥偏偏选中了31呢,请看第二个原因。
第二,31可以被JVM优化,31 * i = (i<<5) - i.。
charAt()
public char charAt(int index) {
// 如果传入的索引大于字符串的长度或者小于0,直接抛出索引越界异常
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
通过传入的索引(数组下标),返回指定索引的单个字符。
compareTo()
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
按字母顺序比较两个字符串,是基于字符串中每个字符的Unicode值。当两个字符串某个位置的字符不同时,返回的是这一位置的字符Unicode值之差,当两个字符串相同时,返回两个字符串长度之差。
compareToIgnoreCase() 方法在 compareTo 方法的基础上忽略大小写,我们知道大写字母是比小写字母的Unicode值小32的,底层实现是先都转换成大写比较,然后都转换成小写进行比较。
concat()
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
首先判断要拼接的字符串长度是否为0,如果为0,则直接返回原字符串。如果部位0,则通过Arrays工具类(后面会详细介绍这个工具类)的copyOf方法创建一个新的字符数组,长度为原字符串之和,情面填充原字符串,后面为空。接着在通过getChars方法将要拼接的字符串放入新字符串后面为空的位置。
indexOf(int ch, int fromIndex)
public int indexOf(int ch, int fromIndex) {
final int max = value.length; // max等于字符的长度
if (fromIndex < 0) { // 指定索引的位置如果小于0,默认从0开始搜索
fromIndex = 0;
} else if (fromIndex >= max) {
// Note: fromIndex might be near -1>>>1.
// 如果指定索引值大于等于字符的长度(因为是数组,下标最多只能是max-1),直接返回-1
return -1;
}
if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
// 一个char占用两个字节,如果ch小于2的16次方(65536),绝大多数字符都在此范围内
// handle most cases here (ch is a BMP code point or a
// negative value (invalid code point))
final char[] value = this.value;
for (int i = fromIndex; i < max; i++) { // for循环依次判断字符串每个字符是否和指定字符相等
if (value[i] == ch) {
return i; // 存在相等的字符,返回第一次出现该字符的索引位置,并终止循环
}
}
return -1; //不存在相等的字符,返回-1
} else { // 当字符大于65536时,处理的少数情况,该方法会首先判断是否是有效字符,然后依次进行比较
return indexOfSupplementary(ch, fromIndex);
}
}
indexOf(int ch),参数 ch 其实是字符的 Unicode 值,这里也可以放单个字符(默认转成int),作用是返回指定字符第一次出现的此字符串中的索引。其内部是调用 indexOf(int ch, int fromIndex),只不过这里的 fromIndex =0 ,因为是从 0 开始搜索;而 indexOf(int ch, int fromIndex) 作用也是返回首次出现的此字符串内的索引,但是从指定索引处开始搜索。