java stringbuffer源码_Java中String、StringBuilder、StringBuffer常用源码分析及比较(一):String源码分析...

String:

一、成员变量:

/**The value is used for character storage.*/

private final charvalue[];/**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;

其中字符数组value[]是String用来存贮字符串的容器,换句话说String是使用字符数组实现的,值得注意的是这个字符数组用到了final修饰,意味着其中的字符串一旦在构造方法中初始化将不能被修改,这也是String字符串在做拼接时,要新建很多String对象的原因;

hash这个变量则是存贮一个String对象的hash值;

String类型实现了Serializable序列化标记接口,所以拥有序列化ID即serialVersionUID。

二、构造方法:

/*** Initializes a newly created {@codeString} object so that it represents

* an empty character sequence. Note that use of this constructor is

* unnecessary since Strings are immutable.*/

publicString() {this.value = new char[0];

}/*** Initializes a newly created {@codeString} object so that it represents

* the same sequence of characters as the argument; in other words, the

* newly created string is a copy of the argument string. Unless an

* explicit copy of {@codeoriginal} is needed, use of this constructor is

* unnecessary since Strings are immutable.

*

*@paramoriginal

* A {@codeString}*/

publicString(String original) {this.value =original.value;this.hash =original.hash;

}/*** Allocates a new {@codeString} so that it represents the sequence of

* characters currently contained in the character array argument. The

* contents of the character array are copied; subsequent modification of

* the character array does not affect the newly created string.

*

*@paramvalue

* The initial value of the string*/

public String(charvalue[]) {this.value =Arrays.copyOf(value, value.length);

}/*** Allocates a new {@codeString} that contains characters from a subarray

* of the character array argument. The {@codeoffset} argument is the

* index of the first character of the subarray and the {@codecount}

* argument specifies the length of the subarray. The contents of the

* subarray are copied; subsequent modification of the character array does

* not affect the newly created string.

*

*@paramvalue

* Array that is the source of characters

*

*@paramoffset

* The initial offset

*

*@paramcount

* The length

*

*@throwsIndexOutOfBoundsException

* If the {@codeoffset} and {@codecount} arguments index

* characters outside the bounds of the {@codevalue} array*/

public String(char value[], int offset, intcount) {if (offset < 0) {throw newStringIndexOutOfBoundsException(offset);

}if (count < 0) {throw newStringIndexOutOfBoundsException(count);

}//Note: offset or count might be near -1>>>1.

if (offset > value.length -count) {throw new StringIndexOutOfBoundsException(offset +count);

}this.value = Arrays.copyOfRange(value, offset, offset+count);

}

其中无参构造方法,可以看到是创建了一个容量为0的char数组,可用性不高;

String(String original)方法,则是将original直接拷贝了一份到新的String中,但别看是拷贝若用“==”去对两个String做判断,结果还是会返回false,因为两者指向的并非同一个地址,都是一个新的String对象;

String(char value[])方法直接调用Arrays.copy方法将参数value拷贝进了String中的value,而Arrays.copy内部的调用如下,是创建了一个新的char数组,而非直接将参数value赋给String中的value,故参数的value与String中的values没有指向同一个地址;

public static char[] copyOf(char[] original, intnewLength) {char[] copy = new char[newLength];

System.arraycopy(original,0, copy, 0,

Math.min(original.length, newLength));returncopy;

}

public String(char value[], int offset, int count)则是将value中的一部分(以下标offset开头,长度为count),复制给了String;

构造方法中还有一个以整型数组为参数的构造方法,如下:

/*** Allocates a new {@codeString} that contains characters from a subarray

* of the Unicode code point array

* argument. The {@codeoffset} argument is the index of the first code

* point of the subarray and the {@codecount} argument specifies the

* length of the subarray. The contents of the subarray are converted to

* {@codechar}s; subsequent modification of the {@codeint} array does not

* affect the newly created string.

*

*@paramcodePoints

* Array that is the source of Unicode code points

*

*@paramoffset

* The initial offset

*

*@paramcount

* The length

*

*@throwsIllegalArgumentException

* If any invalid Unicode code point is found in {@code* codePoints}

*

*@throwsIndexOutOfBoundsException

* If the {@codeoffset} and {@codecount} arguments index

* characters outside the bounds of the {@codecodePoints} array

*

*@since1.5*/

public String(int[] codePoints, int offset, intcount) {if (offset < 0) {throw newStringIndexOutOfBoundsException(offset);

}if (count < 0) {throw newStringIndexOutOfBoundsException(count);

}//Note: offset or count might be near -1>>>1.

if (offset > codePoints.length -count) {throw new StringIndexOutOfBoundsException(offset +count);

}final int end = offset +count;//Pass 1: Compute precise size of char[]

int n =count;for (int i = offset; i < end; i++) {int c =codePoints[i];if(Character.isBmpCodePoint(c))continue;else if(Character.isValidCodePoint(c))

n++;else throw newIllegalArgumentException(Integer.toString(c));

}//Pass 2: Allocate and fill in char[]

final char[] v = new char[n];for (int i = offset, j = 0; i < end; i++, j++) {int c =codePoints[i];if(Character.isBmpCodePoint(c))

v[j]= (char)c;elseCharacter.toSurrogates(c, v, j++);

}this.value =v;

}

可知:这个方法并非简单的将整型数组中的数转成字符(如1转成‘1’),而是找该整数UniCode码对应的字符,传入value数组中,其中isBmpCodePoint方法则是判定这个整数是否在一个码点之内(这个码点是UniCode码表中字符是一个字节还是两个字节的分解线,Unicode码中有一些字符是两个字节,如汉字),若不在这个范围内,自然容量要+1,否则char数组value将装不下。

还有一些构造方法不常用,在此就不做描述;

三、成员方法(列举常用的几个方法)

1.indexOf方法

/*** Returns the index within this string of the first occurrence of

* the specified character. If a character with value

* ch occurs in the character sequence represented by

* this String object, then the index (in Unicode

* code units) of the first such occurrence is returned. For

* values of ch in the range from 0 to 0xFFFF

* (inclusive), this is the smallest value k such that:

*

 
  

* this.charAt(k) == ch

*

* is true. For other values of ch, it is the

* smallest value k such that:

*

 
  

* this.codePointAt(k) == ch

*

* is true. In either case, if no such character occurs in this

* string, then -1 is returned.

*

*@paramch a character (Unicode code point).

*@returnthe index of the first occurrence of the character in the

* character sequence represented by this object, or

* -1 if the character does not occur.*/

public int indexOf(intch) {return indexOf(ch, 0);

}/*** Returns the index within this string of the first occurrence of the

* specified character, starting the search at the specified index.

*

* If a character with value ch occurs in the

* character sequence represented by this String

* object at an index no smaller than fromIndex, then

* the index of the first such occurrence is returned. For values

* of ch in the range from 0 to 0xFFFF (inclusive),

* this is the smallest value k such that:

*

 
  

* (this.charAt(k) == ch) && (k >= fromIndex)

*

* is true. For other values of ch, it is the

* smallest value k such that:

*

 
  

* (this.codePointAt(k) == ch) && (k >= fromIndex)

*

* is true. In either case, if no such character occurs in this

* string at or after position fromIndex, then

* -1 is returned.

*

*

* There is no restriction on the value of fromIndex. If it

* is negative, it has the same effect as if it were zero: this entire

* string may be searched. If it is greater than the length of this

* string, it has the same effect as if it were equal to the length of

* this string: -1 is returned.

*

*

All indices are specified in char values

* (Unicode code units).

*

*@paramch a character (Unicode code point).

*@paramfromIndex the index to start the search from.

*@returnthe index of the first occurrence of the character in the

* character sequence represented by this object that is greater

* than or equal to fromIndex, or -1

* if the character does not occur.*/

public int indexOf(int ch, intfromIndex) {final int max =value.length;if (fromIndex < 0) {

fromIndex= 0;

}else if (fromIndex >=max) {//Note: fromIndex might be near -1>>>1.

return -1;

}if (ch

final char[] value = this.value;for (int i = fromIndex; i < max; i++) {if (value[i] ==ch) {returni;

}

}return -1;

}else{returnindexOfSupplementary(ch, fromIndex);

}

}

由于第一个方法调用的是第二个方法,主要看第二个方法:

其实我们从之前看到的代码就可以知道,Java的健壮性非常好,因为每一个具体的方法都有对数组是否越界、参数是否合理做了判断并处理。

这个方法是根据传入整型根据Unicode码来查找对应字符串的,fromIndex则是表示从第几个字符开始查找,该方法同样要考虑到有些字占两个字节的情况,不过看完这个方法,可以看出,Java语言对于查找这件事情也没有太好的方法,它也只能遍历char数组来查找对应字符。

/*** Returns the index within this string of the first occurrence of the

* specified substring.

*

*

The returned index is the smallest value k for which:

*

 
 

* this.startsWith(str, k)

*

* If no such value of k exists, then {@code-1} is returned.

*

*@paramstr the substring to search for.

*@returnthe index of the first occurrence of the specified substring,

* or {@code-1} if there is no such occurrence.*/

public intindexOf(String str) {return indexOf(str, 0);

}/*** Returns the index within this string of the first occurrence of the

* specified substring, starting at the specified index.

*

*

The returned index is the smallest value k for which:

*

 
  

* k >= fromIndex && this.startsWith(str, k)

*

* If no such value of k exists, then {@code-1} is returned.

*

*@paramstr the substring to search for.

*@paramfromIndex the index from which to start the search.

*@returnthe index of the first occurrence of the specified substring,

* starting at the specified index,

* or {@code-1} if there is no such occurrence.*/

public int indexOf(String str, intfromIndex) {return indexOf(value, 0, value.length,

str.value,0, str.value.length, fromIndex);

}/*** Code shared by String and StringBuffer to do searches. The

* source is the character array being searched, and the target

* is the string being searched for.

*

*@paramsource the characters being searched.

*@paramsourceOffset offset of the source string.

*@paramsourceCount count of the source string.

*@paramtarget the characters being searched for.

*@paramtargetOffset offset of the target string.

*@paramtargetCount count of the target string.

*@paramfromIndex the index to begin searching from.*/

static int indexOf(char[] source, int sourceOffset, intsourceCount,char[] target, int targetOffset, inttargetCount,intfromIndex) {if (fromIndex >=sourceCount) {return (targetCount == 0 ? sourceCount : -1);

}if (fromIndex < 0) {

fromIndex= 0;

}if (targetCount == 0) {returnfromIndex;

}char first =target[targetOffset];int max = sourceOffset + (sourceCount -targetCount);for (int i = sourceOffset + fromIndex; i <= max; i++) {/*Look for first character.*/

if (source[i] !=first) {while (++i <= max && source[i] !=first);

}/*Found first character, now look at the rest of v2*/

if (i <=max) {int j = i + 1;int end = j + targetCount - 1;for (int k = targetOffset + 1; j < end &&source[j]== target[k]; j++, k++);if (j ==end) {/*Found whole string.*/

return i -sourceOffset;

}

}

}return -1;

}

参数为String类型的同理,不过是变成了查找匹配字符串的第一个下标,同样用的是遍历,不过在此我发现一个我原来不知道的情况,如下:

public int indexOf(String str, intfromIndex) {return indexOf(value, 0, value.length,

str.value,0, str.value.length, fromIndex);

}

str竟然可以可以直接用过‘.’语法直接得到value,value可是用private修饰的,OH!,于是我用一个Test来验证了一下,如下:

public classStrInnerTestBean {private final char[] str;publicStrInnerTestBean() {this.str = new char[]{'h','e','l','l','o'};

}public static voidtest(StrInnerTestBean bean){

System.out.println(bean.str);

}public static voidmain(String[] args) {

test(newStrInnerTestBean());

}

}

可以看出若传入参数是该类一个对象,就可直接通过'.'语法获得private修饰的值,若不是该类的对象则不可。

2.subString方法

/*** Returns a new string that is a substring of this string. The

* substring begins with the character at the specified index and

* extends to the end of this string.

* Examples:

*

 
  

* "unhappy".substring(2) returns "happy"

* "Harbison".substring(3) returns "bison"

* "emptiness".substring(9) returns "" (an empty string)

*

*

*@parambeginIndex the beginning index, inclusive.

*@returnthe specified substring.

*@exceptionIndexOutOfBoundsException if

* beginIndex is negative or larger than the

* length of this String object.*/

public String substring(intbeginIndex) {if (beginIndex < 0) {throw newStringIndexOutOfBoundsException(beginIndex);

}int subLen = value.length -beginIndex;if (subLen < 0) {throw newStringIndexOutOfBoundsException(subLen);

}return (beginIndex == 0) ? this : newString(value, beginIndex, subLen);

}/*** Returns a new string that is a substring of this string. The

* substring begins at the specified beginIndex and

* extends to the character at index endIndex - 1.

* Thus the length of the substring is endIndex-beginIndex.

*

* Examples:

*

 
  

* "hamburger".substring(4, 8) returns "urge"

* "smiles".substring(1, 5) returns "mile"

*

*

*@parambeginIndex the beginning index, inclusive.

*@paramendIndex the ending index, exclusive.

*@returnthe specified substring.

*@exceptionIndexOutOfBoundsException if the

* beginIndex is negative, or

* endIndex is larger than the length of

* this String object, or

* beginIndex is larger than

* endIndex.*/

public String substring(int beginIndex, intendIndex) {if (beginIndex < 0) {throw newStringIndexOutOfBoundsException(beginIndex);

}if (endIndex >value.length) {throw newStringIndexOutOfBoundsException(endIndex);

}int subLen = endIndex -beginIndex;if (subLen < 0) {throw newStringIndexOutOfBoundsException(subLen);

}return ((beginIndex == 0) && (endIndex == value.length)) ? this:newString(value, beginIndex, subLen);

}

这个方法很简单,就是创建一个String将value根据下标进行截取再传入就可,但是需要注意的是若没有对String进行截取,会怎么做,还会创建一个新String,copy一份吗,从代码中可以看到,若没有截取,是直接将当前对象返回并未新建String。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值