您的位置:首页 > 编程语言 > Java开发

Java String 源代码分析

2016-03-03 22:00 507 查看
String类的字段主要有下面几个:

final char value[], 字符数组主要用于存放字符

final int offset,字符数组的第一个元素下标

final int count,字符数组中元素的数量统计

int hash,字符串的hash值

构造函数

如果我们平时这样定义数组,那么会得到一个空的字符数组,并且是不可变的。

String str = new String();

public String() {
this.offset = 0;
this.count = 0;
this.value = new char[0];
}


下一种使用字符串来初始化对象:

String str = new String(“abc”);

这里代码中处理了如果初始化的字符串两边有垃圾字符,或者是空格等的情况,会删除掉这些字符。

public String(String original) {
int size = original.count;
char[] originalValue = original.value;
char[] v;
if (originalValue.length > size) {
// The array representing the String is bigger than the new
// String itself.  Perhaps this constructor is being called
// in order to trim the baggage, so make a copy of the array.
int off = original.offset;
v = Arrays.copyOfRange(originalValue, off, off+size);
} else {
// The array representing the String is the same
// size as the String, so no point in making a copy.
v = originalValue;
}
this.offset = 0;
this.count = size;
this.value = v;
}


使用字符数组构造字符串

String str = new String(new char[]{‘a’,’b’});

public String(char value[]) {
int size = value.length;
this.offset = 0;
this.count = size;
this.value = Arrays.copyOf(value, size);
}


其他还有很多灵活的构造函数,但是大多使用了Arrays的方法。

常用方法

返回字符串长度

public int length() {
return count;
}


判断字符串是否为空

public boolean isEmpty() {
return count == 0;
}


根据下标查找元素:

public char charAt(int index) {
if ((index < 0) || (index >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index + offset];
}


判断字符串相等

public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}


从这里可以看出,字符串相等的比较,是先检查字符串的长度是否相同,如果相同,则每一个字符元素进行比较,如果有其中一个不一样,则返回false。

字符串比较

public int compareTo(String anotherString) {
int len1 = count;
int len2 = anotherString.count;
int n = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;

if (i == j) {
int k = i;
int lim = n + i;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
} else {
while (n-- != 0) {
char c1 = v1[i++];
char c2 = v2[j++];
if (c1 != c2) {
return c1 - c2;
}
}
}
return len1 - len2;
}


这个方法就比较玄妙了,首先将参数字符串的相关字段全部都复制一份出来,然后判断两个字符数组第一个元素下标是否相同。

如果相同:从下标开始到较小长度字符串进行循环,每个字符进行比较,如果遇到字符不相等的情况,则做减法。

如果不同,也是从按照较小长度字符串的数据进行循环,每个字符进行比较做减法。

startsWith(String prefix)

public boolean startsWith(String prefix) {
return startsWith(prefix, 0);
}
public boolean startsWith(String prefix, int toffset) {
char ta[] = value;
int to = offset + toffset;
char pa[] = prefix.value;
int po = prefix.offset;
int pc = prefix.count;
// Note: toffset might be near -1>>>1.
if ((toffset < 0) || (toffset > count - pc)) {
return false;
}
while (--pc >= 0) {
if (ta[to++] != pa[po++]) {
return false;
}
}
return true;
}


这里调用了另外一个startsWith方法,传入了从第几个元素下标开始比较。默认都是0.

这里做的也是遍历传入字符串的每一个元素,判断是否相同。

hashcode()

public int hashCode() {
int h = hash;
if (h == 0 && count > 0) {
int off = offset;
char val[] = value;
int len = count;

for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}


计算hashcode的方法使用了这个公式。

h = 31*h+val[off++]

hashcode的要求是,同一个字符串不论这个方法调用多少次,这个值总是不变的。而且不能和其他字符串计算出来的值一样。这样会造成冲突。就是说纯粹是为了确保唯一性。

这里使用31的原因是,31在CPU上做乘法时,采用左移计算性能更高。来自网络资料。

intern()

这个方法应该算是String类里面唯一一个不是用Java实现的了。其源代码如下:

public native String intern();

说明是个本地方法,用C++来实现的。这个方法的作用是什么呢?

先要说下字符串定义的方式:

String str = “abc”;

这种方式也可以定义字符串,不过定义的字符串全部都在常量池中有储存,如果一个String类型的对象调用了intern方法的话,那么会检查这个字符串是否在常量池中有相等的String,如果有则返回常量池的对象,如果没有,则在常量池中定义一个。这样做的办法是性能会好很多,String不在堆上。

看一个例子:

package com.lenovo;
public class StringTest {
public static void main(String[] args) {
String a = "abc";
String b = new String("abc");
System.out.println(a==b);
System.out.println(a==b.intern());
System.out.println(a.equals(b));
}
}


这个输出是:

false

true

true

显然,a,b不是同一个,但是b调用了intern方法后,就是和a同一个对象了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 源代码 string