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。