java.lang.String类的源码分析
String类是java中比较常见的一个类,今天有空来看一下string的部分源码。
先构造一个string对象
String str = new String ("hello world!!!");
这句代码,查看源代码如下:
public String(String original) {//传进来hello world
int size = original.count;//把长度赋值给size 这里是14
//这里的value是一个数组 private final char value[],
//用来存放character,应该是先把字符串转换成数组,再赋值给originalValue
char[] originalValue = original.value;
char[] v;
//如果新数组的长度大于size 把数组copy到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.
//这里执行是else中的语句
v = originalValue;
}
this.offset = 0;
this.count = size;
this.value = v;
}
debug模式下查看str对象的内容:
各个方法的源码:
1.str.length():返回此字符串的长度。
//不多说大家一看就懂
public int length() {
return count;
}
2.str.charAt(3):返回指定索引处的 char 值。
public char charAt(int index) {//将3传进来
//判断是否越界
if ((index < 0) || (index >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
//直接返回index躲在位置上的字符,这里的offset是0
return value[index + offset];
}
3.str.compareTo(“123”):按字典顺序比较两个字符串
public int compareTo(String anotherString) {//123
int len1 = count;//str的字符串长度
int len2 = anotherString.count;//123的长度
int n = Math.min(len1, len2);//调用Math取最小值
char v1[] = value;//代表的是hello world!!!
char v2[] = anotherString.value;//123
int i = offset;//0
int j = anotherString.offset;//应该也是0
if (i == j) {//i==j时
int k = i;//k = 0
int lim = n + i;//lim = 3 +0,这里加上offset个人认为可能有时候需要从某个位置开始比较
while (k < lim) {//循环判断,直到找到第一个不相等的数值,返回两个字符的差值
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
} else {
//当指定了offset时,进入到这里
while (n-- != 0) {
//从指定的offset向后比较,找到第一个不相等的,返回差值
char c1 = v1[i++];
char c2 = v2[j++];
if (c1 != c2) {
return c1 - c2;
}
}
}
return len1 - len2;
}
4.str.compareToIgnoreCase(“Hell”): 按字典顺序比较两个字符串,不考虑大小写,和上面的差不多 ,只是多了一部转换成相同的大小写
public int compare(String s1, String s2) {
int n1=s1.length(), n2=s2.length();
for (int i1=0, i2=0; i1<n1 && i2<n2; i1++, i2++) {
char c1 = s1.charAt(i1);
char c2 = s2.charAt(i2);
if (c1 != c2) {
c1 = Character.toUpperCase(c1);
c2 = Character.toUpperCase(c2);
if (c1 != c2) {
c1 = Character.toLowerCase(c1);
c2 = Character.toLowerCase(c2);
if (c1 != c2) {
return c1 - c2;
}
}
}
}
return n1 - n2;
}
}
str.concat(“hello java”):将指定字符串连接到此字符串的结尾。
public String concat(String str) {
//得到新字符串的长度
int otherLen = str.length();
//如果长度为0直接返回原始字符串
if (otherLen == 0) {
return this;
}
//当str长度不为0时,重新定义一个新的字符数组
char buf[] = new char[count + otherLen];
//把老的字符串拷贝到buf里面
getChars(0, count, buf, 0);
//getchar源码如下:
/**
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > count) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
拷贝数组
各个参数的意思:1:要复制的数组
2:从那个位置开始复制
3:要复制到那个数组里面
4:复制到数组从第几个位置开始
5:复制的长度
System.arraycopy(value, offset + srcBegin, dst, dstBegin,
srcEnd - srcBegin);
}
*/
//调用str的getChar把hello java 复制到数组buf里面
str.getChars(0, otherLen, buf, count);
//返回新数组,并重新定义相应的字段值
return new String(0, count + otherLen, buf);
}
str.contains(“llo”):当且仅当此字符串包含指定的 char 值序列时,返回 true。
static int indexOf(char[] source, int sourceOffset, int sourceCount,
char[] target, int targetOffset, int targetCount,
int fromIndex) {
//当偏移量大于原始数组的长度,也就是说,target数组开始比较的位置比原始数组的长度还大,显然没法比较
if (fromIndex >= sourceCount) {
//目标数组的长度为0 返回原数组的长度,否则返回-1
return (targetCount == 0 ? sourceCount : -1);
}
if (fromIndex < 0) {
fromIndex = 0;
}
//如果你的目标数组是空字符串,这里也认为空字符串实在目标字符串中包含着的,会返回true
if (targetCount == 0) {
return fromIndex;
}
char first = target[targetOffset];//从target的offset处开始比较
/**
* 最多比较的次数,这里比较经典,例如"hello world".contains("nihao");
* 因为偏移量是0所以方法会先比较h 和 n 不想等 继续向后走 直到走到 w 和 n 依然不想等 ,那么就不要再比较了 ,因为剩下的肯定就不会再相等了
*/
int max = sourceOffset + (sourceCount - targetCount);
for (int i = sourceOffset + fromIndex; i <= max; i++) {
//第一个元素不想等
if (source[i] != first) {
//进入while i++ 再次比较 第一个元素 知道相等在跳出while,这里采用++i为了减少第一个元素比较两次 ,赞
while (++i <= max && source[i] != first);
}
/* Found first character, now look at the rest of v2 */
//如果第一个元素相等,并且i还小于max
if (i <= max) {
int j = i + 1;//从下一个元素开始
int end = j + targetCount - 1;
//如果元素想等就一直向下走,直到遇到一个不想等的跳出for循环
for (int k = targetOffset + 1; j < end && source[j] ==
target[k]; j++, k++);
//如果走到了目标元素的尾部,说明原数组中包含目标数组
if (j == end) {
/* Found whole string. */
//返回匹配的第一个元素下标
return i - sourceOffset;
}
}
//否则继续向后走,知道下标越界跳出循环
}
return -1;
}