由于水平问题只能对String能够理解的部分进行简单说明。
一、String的类声明
String的类声明部分的代码:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
String类加了final声明,也就意味着String不能被继承,其将类声明为final的主要作用是:
- 由于String类不能被继承,所以就不会没修改,这就避免了因为继承引起的安全隐患,因为java很多方法都是“本地方法调用”,如果重写了这些方法就可能对系统进行恶意攻击。
- String类在程序中出现的频率比较高,如果为了避免安全隐患,在它每次出现时都用final来修饰,这无疑会降低程序的执行效率,所以干脆直接将其设为final以提高效率(在使用final修饰方法的时候,编译器会将被final修饰过的方法插入到调用者代码处,提高运行速度和效率)。
String类实现了Serializable使得String可以进行序列化
String类实现了Comparable接口,Comparable接口主要有一个compareTo()方法,这个方法主要用于两个实例之间的比较,方便与String在集合中进行排序。
String实现了CharSequence,代表String是一个可读的字符序列,String, StringBuilder和StringBuffer本质上都是通过字符数组实现的,他们都实现了CharSequence接口,为外部提供了对于他们的内部字符数组的统一读取方法。
二、String成员变量
String成员变量有三个:
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
其中比较重要的是value[],它的作用就是用来保存String的值。它是由final修饰,也就是说不能修改value指向的char数组,但是能够修改value[]数组保存的值。但是String并没有对外提供修改value的方法,并且String 类使用final声明,也就是说我们无法修改value的值。这也就确保了String一经创建他的值就无法修改。
serialVersionUID和serialPersistentFields是序列化时使用的
三、String方法
string的方法有很多,其方法大部分都是对于value进行操作,这里挑几个方法来看一下
1.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;
}
String的hashCode是由value的值来决定的,String的值相同他们的hashCode也相同。这里使用31作为乘积有一下原因:
a.31是质子数中一个“不大不小”的存在,如果你使用的是一个如2的较小质数,那么得出的乘积会在一个很小的范围,很容易造成哈希值的冲突。而如果选择一个100以上的质数,得出的哈希值会超出int的最大范围,这两种都不合适。而如果对超过 50,000 个英文单词(由两个不同版本的 Unix 字典合并而成)进行 hash code 运算,并使用常数 31, 33, 37, 39 和 41 作为乘子,每个常数算出的哈希值冲突数都小于7个(国外大神做的测试),那么这几个数就被作为生成hashCode值得备选乘数了。
b.JVM里最有效的计算方式就是进行位运算了:
-
左移 << : 左边的最高位丢弃,右边补全0(把 << 左边的数据*2的移动次幂)。
-
右移 >> : 把>>左边的数据/2的移动次幂。
-
无符号右移 >>> : 无论最高位是0还是1,左边补齐0。
所以 : 31 * i = (i << 5) - i(左边 312=62,右边 22^5-2=62) - 两边相等,JVM就可以高效的进行计算
2.实现了Comparable的conpareTo方法
方法实现比较简单,逐个比较字符数组中的值然后返回结果。
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;
}
3.intern方法
intern方法的作用是返回字符串对象的规范化表示形式,当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。,native关键字标注的方法就表示是本地调用方法,方法体里面没有显示实现,它是不是由java实现的。
public native String intern();