文章目录
- String 部分源码阅读
- 类声明
- String 字段解释
- String 构造方法阅读
- public String(char value[], int offset, int count)
- public String(int[] codePoints, int offset, int count)
- 查询
- 关于char
- charAt()
- startsWith()、endsWith()
- 关于codePoint
- codePointAt()
- codePointBefore()
- codePointCount()
- offsetByCodePoints()
- contains()
- 关于index
- indexOf()
- lastIndexOf()
- 比较
- 关于compare
- compareTo()
- compareToIgnoreCase()
- 关于equals
- equals()
- equalsIgnoreCase()
- contentEquals()
- 关于matches
- matches()
- regionMatches()
- 替换
- repalce()
- replaceFirst()
- replaceAll()
- 截取
- subSequence()
- subString()
- 赋值
- copyValueOf()
- getChars()
- 连接
- concat()
- 分割
- split()
- 转换
- format()
- intern()
- getBytes()
- toCharArray()
- toUpperCase()
- toLowerCase()
- toString()
- valueOf()
- 其他
- trim()
- hashCode()
- isEmpty()
- length()
String 部分源码阅读
类声明
public final class String implements java.io.Serializable, Comparable, CharSequence
String类是一个公有的、不可更改的的类,实现了三个接口:
Serializable(实现后String是可序列化的)
Comparable(实现CompareTo(String s)方法,用于String的比较)
CharSequence(其中
lenth()返回字符串长度,
charAt(int index)可以获取index处的字符,
subSequence(int start ,int end),顾名思义,sub表示“子的,次的”,再结合给出的参数arguement start 和end,可以知道这个是求取子字符串,
toString()方法是将对象转化成需要的字符串再返回,对于String对象,则是返回String自己
String 字段解释
String源码详解
String 构造方法阅读
String有很多构造方法,有参无参和不同类型的参数,这里就选取自己跳跳能够得着的几个方法进行分析(后来不小心把所有源码都复制了上来,但是还有很多没有分析理解的)
public String(char value[], int offset, int count)
- 这一段是对此方法的总注解,仔细读读可以知道方法的大体功能,将一段子数组赋给创建的新String,同时要注意开端位置offset和将要被复制字符个数count的合法性。
Allocates a new {@code String} that contains characters from a subarray
of the character array argument. The {@code offset} argument is the
index of the first character of the subarray and the {@code count}
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.
- 下面是对方法具体参数的注解,
@param value
Array that is the source of characters
@param offset
The initial offset
@param count
The length
@throws IndexOutOfBoundsException
If the {@code offset} and {@code count} arguments index
characters outside the bounds of the {@code value} array
其中,
@param
command @param param denotes following word is name of the parameter and following text is description of the parameter; all parameters are placed in a list
表示 接下来是参数的名字和对它的描述
@code
To mark some text as a code in documentation, code and endcode commands are used.
为了将某些文本标记为代码,使用code 和endcode
- 再看具体实现代码
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}//如果count为0且offset合法,则新创建的数组长度为0,但没有存任何东西
}
// 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);
}
这里的Note注释和大小比较时奇怪的摆放位置肯定让大家困惑,可以参考链接里的一个解释
Note: offset or count might be near -1>>>1.
public String(int[] codePoints, int offset, int count)
- 大体注释
Allocates a new {@code String} that contains characters from a subarray
of the <a href="Character.html#unicode">Unicode code point</a> array
argument. The {@code offset} argument is the index of the first code
point of the subarray and the {@code count} argument specifies the
length of the subarray. The contents of the subarray are converted to
{@code char}s; subsequent modification of the {@code int} array does not
affect the newly created string.
和上一种实现方法的解释相比,增加了几个需要注意的点,1.来源是一个存放代码点的数组,2.规定了第一个要复制的字符和长度之后,将代码点转化成对应的字符,再放进新数组。
关于代码点的知识,这里附上链接,可以理解成是一种表示字符的编码,就像ascii码一样
代码点(Code Point)和代码单元(Code Unit)
- 具体实现代码
public String(int[] codePoints, int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= codePoints.length) {
this.value = "".value;
return;
}
}
// 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 new IllegalArgumentException(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;
else
Character.toSurrogates(c, v, j++);
}
this.value = v;
}
本人水平还不够,没法讲清楚,供大家自己思考吧
之后下面的代码,容易理解的就直接放实现方法了
查询
关于char
charAt()
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
对于下标index,必须要检查它的合法性,过大过小都会抛出异常
startsWith()、endsWith()
public boolean startsWith(String prefix, int toffset) {
char ta[] = value;
int to = toffset;
char pa[] = prefix.value;
int po = 0;
int pc = prefix.value.length;
// Note: toffset might be near -1>>>1.
if ((toffset < 0) || (toffset > value.length - pc)) {
return false;
}
while (--pc >= 0) {
if (ta[to++] != pa[po++]) {
return false;
}
}
return true;
}
判断从toffset开始的String 字串是否以prefix 开头,
先定义局部变量存储传入的prefix和toffset,
照例对索引进行范围判断,
然后是熟悉地遍历数组,判断每个字符就好
public boolean startsWith(String prefix) {
return startsWith(prefix, 0);
}
没有toffset传入就默认是0
关于codePoint
codePointAt()
public int codePointAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointAtImpl(value, index, value.length);
}
返回指定位置的代码点(Unicode编码)
首先判断index的合法性
再而用Character的codePointAtImpl方法返回对应的Unicode值
对于此引用的方法,附上链接,讲得很清楚(总之就是要知道这个位置字符的编码,但是有个小问题:有些比较“肥”的字符占据了两个数组位置,所以它的编码是两个位置合起来的结果)
Java学习笔记6 - Unicode编码与UTF-16
codePointBefore()
public int codePointBefore(int index) {
int i = index - 1;
if ((i < 0) || (i >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointBeforeImpl(value, index, 0);
}
这里则是返回index前一个位置的代码点(字符的编码),用到了Character.codePointBeforeImpl
codePointCount()
public int codePointCount(int beginIndex, int endIndex) {
if (beginIndex < 0 || endIndex > value.length || beginIndex > endIndex) {
throw new IndexOutOfBoundsException();
}
return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex);
}
返回给定范围内的代码点数量,代码点数量就是字符个数,但有些字符比较“肥”,占了数组中两个位置,所以这个方法还是有必要的;
当开始下标为负或结束下标超出数组长度(结束下标一般不被包括,所以最大可以为数组长度)或开始下标大于结束下标时,异常。咦?那假如开始等于结束呢,不清楚,好像也不行欸,欢迎大家发表想法。
offsetByCodePoints()
public int offsetByCodePoints(int index, int codePointOffset) {
if (index < 0 || index > value.length) {
throw new IndexOutOfBoundsException();
}
return Character.offsetByCodePointsImpl(value, 0, value.length,
index, codePointOffset);
}
返回此String中从给定索引index处偏移codePointOffset个代码点的索引
String str = "hello";
int n = str.offsetByCodePoints(0,3);
System.out.println(n);//输出 3;
contains()
public boolean contains(CharSequence s) {
return indexOf(s.toString()) > -1;
}
哦哦,只要看看它的下标是不是大于-1就好啦,因为在indexOf的方法里,不符合的都返回-1了!
关于index
indexOf()
public int indexOf(int ch, int fromIndex) {
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 < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
// handle most cases here (ch is a BMP code point or a
// negative value (invalid code point))
final char[] value = this.value;
for (int i = fromIndex; i < max; i++) {
if (value[i] == ch) {
return i;
}
}
return -1;
} else {
return indexOfSupplementary(ch, fromIndex);
}
}
从指定的offset处查找字符ch 在字符串中出现的第一个位置
若offset为负,结果会同offset为0一样,若offset大于等于字符串长,均会返回-1;
若ch是占两个字节,也就是一个数组位置的字符,那么就从offset位置遍历字符串进行比较,返回正确的下标,没有则返回-1;
若ch占4个字节,也就是两个数组位置,那么采用indexOfSupplementary方法,(找寻增补字符的下标的方法)也就是两个数组位置上的“子字符”都要相等才能说明这个字符相等。
当然,indexOf还有很多形参类型,比如将字符换成字符串等。
lastIndexOf()
public int lastIndexOf(int ch, int fromIndex) {
if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
// handle most cases here (ch is a BMP code point or a
// negative value (invalid code point))
final char[] value = this.value;
int i = Math.min(fromIndex, value.length - 1);
for (; i >= 0; i--) {
if (value[i] == ch) {
return i;
}
}
return -1;
} else {
return lastIndexOfSupplementary(ch, fromIndex);
}
}
哈哈,其实就是倒着找第一个出现的就好啦,和上面的indexOf基本类似
比较
关于compare
compareTo()
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;
}
比较两个String,但是会返回他们的字符差值或是长度差值,代码简单清晰,很是好看纳
先用len1和len2保存长度,lim存放短一点的长度,v1和v2是两个数组,将两个数组中字符一一比较,中途若有不等,返回字符差值,否则是直到一方数组已经结束,这时两个数组只有长度上的差异,返回长度差值
compareToIgnoreCase()
忽略大小写,进行比较
关于equals
equals()
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
判断一个对象的内容是否与此String相等,
若二者“==”成立,则一定相等, 等号是判断对象是否一样,equals是判断二者内容是否相同,等号要求更严;
anObject instanceof String,instanceof的左边是对象,右边是类或接口,当左边的对象是右边类或子类实现的对象时,返回true,否则返回false,在对引用数据类进行强制转换时会用到;
转换之后对二者的每个字符一一遍历,只有全部相等时才返回true,否则,只要有一个不等,或是instanceof返回为false,则整个方法返回false
equalsIgnoreCase()
public boolean equalsIgnoreCase(String anotherString) {
return (this == anotherString) ? true
: (anotherString != null)
&& (anotherString.value.length == value.length)
&& regionMatches(true, 0, anotherString, 0, value.length);
}
contentEquals()
public boolean contentEquals(CharSequence cs) {
// Argument is a StringBuffer, StringBuilder
if (cs instanceof AbstractStringBuilder) {
if (cs instanceof StringBuffer) {
synchronized(cs) {
return nonSyncContentEquals((AbstractStringBuilder)cs);
}
} else {
return nonSyncContentEquals((AbstractStringBuilder)cs);
}
}
// Argument is a String
if (cs instanceof String) {
return equals(cs);
}
// Argument is a generic CharSequence
char v1[] = value;
int n = v1.length;
if (n != cs.length()) {
return false;
}
for (int i = 0; i < n; i++) {
if (v1[i] != cs.charAt(i)) {
return false;
}
}
return true;
}
暂时还没达到那个水平分析,先放放
关于matches
matches()
public boolean matches(String regex) {
return Pattern.matches(regex, this);
}
pan’d
regionMatches()
public boolean regionMatches(int toffset, String other, int ooffset,
int len) {
char ta[] = value;
int to = toffset;
char pa[] = other.value;
int po = ooffset;
// Note: toffset, ooffset, or len might be near -1>>>1.
if ((ooffset < 0) || (toffset < 0)
|| (toffset > (long)value.length - len)
|| (ooffset > (long)other.value.length - len)) {
return false;
}
while (len-- > 0) {
if (ta[to++] != pa[po++]) {
return false;
}
}
return true;
}
判断两个String在指定区域内是否内容相同,思路在方法前的解释都写得很清楚,参数是offset、other string、toffset和len,两个起始位置,另一个字符串,和它们的长度
先判断给定索引是否合法,不合法返回false
再对两个字符串的字符遍历比较,中途有不同的可以直接返回false,只有当索引合法且均相同时才返回true
还有另一种参数形式,更麻烦一些应该,这里就不分析啦
替换
repalce()
public String replace(char oldChar, char newChar) {
if (oldChar != newChar) {
int len = value.length;
int i = -1;
char[] val = value; /* avoid getfield opcode */
while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
if (i < len) {
char buf[] = new char[len];
for (int j = 0; j < i; j++) {
buf[j] = val[j];
}
while (i < len) {
char c = val[i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
return new String(buf, true);
}
}
return this;
}
将一个字符串中的所有某种字符替换成另一种字符,是先将前面所有非需要替换字符赋给一个新数组,之后若遇到要替换的字符,换,否则,直接放进去;你可能会想,为什么不直接替换呢,非要新建,本来以为和增补字符有关,后来查了一查,源码的设计很精妙,在最后不需替换的字符串和长字符串面前,效率比直接替换快的多,突然又感受到数据结构的神奇代码魅力了,这里有相关回答:
为什么replace源码那么长
replaceFirst()
public String replaceFirst(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
}
将第一次出现的regex正则表达式替换成replacement字符串
replaceAll()
public String replaceAll(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
将所有regex字符串均替换
截取
subSequence()
public CharSequence subSequence(int beginIndex, int endIndex) {
return this.substring(beginIndex, endIndex);
}
哈哈,官方发话,就是下一个方法
subString()
public String substring(int beginIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}
返回从指定位置开始的子串,首先依旧是对offset合法性的判断,抛出不同异常,最后返回是原本的或是新建的一个字符串,思路还是比较简单的
赋值
copyValueOf()
getChars()
void getChars(char dst[], int dstBegin) {
System.arraycopy(value, 0, dst, dstBegin, value.length);
}
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
void getChars(char dst[], int dstBegin)
将String 中的字符传到dst数组中,从dstBegin开始传;
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin)
将String中子串传过去,同样注意索引(下标)的合法性
连接
concat()
public String concat(String str) {
if (str.isEmpty()) {
return this;
}
int len = value.length;
int otherLen = str.length();
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
将一个字符串连接到另一个后面
是采用新建一个buf数组的方式,先将value传入,再将str传进去,再返回即可(我的暂时很浅显,没有细细去看)
分割
split()
public String[] split(String regex, int limit) {
/* fastpath if the regex is a
(1)one-char String and this character is not one of the
RegEx's meta characters ".$|()[{^?*+\\", or
(2)two-char String and the first char is the backslash and
the second is not the ascii digit or ascii letter.
*/
char ch = 0;
if (((regex.value.length == 1 &&
".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
(regex.length() == 2 &&
regex.charAt(0) == '\\' &&
(((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
((ch-'a')|('z'-ch)) < 0 &&
((ch-'A')|('Z'-ch)) < 0)) &&
(ch < Character.MIN_HIGH_SURROGATE ||
ch > Character.MAX_LOW_SURROGATE))
{
int off = 0;
int next = 0;
boolean limited = limit > 0;
ArrayList<String> list = new ArrayList<>();
while ((next = indexOf(ch, off)) != -1) {
if (!limited || list.size() < limit - 1) {
list.add(substring(off, next));
off = next + 1;
} else { // last one
//assert (list.size() == limit - 1);
list.add(substring(off, value.length));
off = value.length;
break;
}
}
// If no match was found, return this
if (off == 0)
return new String[]{this};
// Add remaining segment
if (!limited || list.size() < limit)
list.add(substring(off, value.length));
// Construct result
int resultSize = list.size();
if (limit == 0) {
while (resultSize > 0 && list.get(resultSize - 1).isEmpty()) {
resultSize--;
}
}
String[] result = new String[resultSize];
return list.subList(0, resultSize).toArray(result);
}
return Pattern.compile(regex).split(this, limit);
}
split好长,之后再来看吧……
转换
format()
public static String format(String format, Object... args) {
return new Formatter().format(format, args).toString();
}
intern()
public native String intern();
getBytes()
public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
Objects.requireNonNull(dst);
int j = dstBegin;
int n = srcEnd;
int i = srcBegin;
char[] val = value; /* avoid getfield opcode */
while (i < n) {
dst[j++] = (byte)val[i++];
}
}
将给定子串转化 为dst字节数组的一部分(从dstBegin开始)
先对索引进行判断,
Objects.requireNonNull(dst);是判断对象 dst数组是否为空,若空,则报异常;
之后再一个一个地强制转换,赋给dst数组
还有很多其他参数的getBytes方法,这里就不看啦
toCharArray()
public char[] toCharArray() {
// Cannot use Arrays.copyOf because of class initialization order issues
char result[] = new char[value.length];
System.arraycopy(value, 0, result, 0, value.length);
return result;
}
toUpperCase()
public String toUpperCase(Locale locale) {
if (locale == null) {
throw new NullPointerException();
}
int firstLower;
final int len = value.length;
/* Now check if there are any characters that need to be changed. */
scan: {
for (firstLower = 0 ; firstLower < len; ) {
int c = (int)value[firstLower];
int srcCount;
if ((c >= Character.MIN_HIGH_SURROGATE)
&& (c <= Character.MAX_HIGH_SURROGATE)) {
c = codePointAt(firstLower);
srcCount = Character.charCount(c);
} else {
srcCount = 1;
}
int upperCaseChar = Character.toUpperCaseEx(c);
if ((upperCaseChar == Character.ERROR)
|| (c != upperCaseChar)) {
break scan;
}
firstLower += srcCount;
}
return this;
}
/* result may grow, so i+resultOffset is the write location in result */
int resultOffset = 0;
char[] result = new char[len]; /* may grow */
/* Just copy the first few upperCase characters. */
System.arraycopy(value, 0, result, 0, firstLower);
String lang = locale.getLanguage();
boolean localeDependent =
(lang == "tr" || lang == "az" || lang == "lt");
char[] upperCharArray;
int upperChar;
int srcChar;
int srcCount;
for (int i = firstLower; i < len; i += srcCount) {
srcChar = (int)value[i];
if ((char)srcChar >= Character.MIN_HIGH_SURROGATE &&
(char)srcChar <= Character.MAX_HIGH_SURROGATE) {
srcChar = codePointAt(i);
srcCount = Character.charCount(srcChar);
} else {
srcCount = 1;
}
if (localeDependent) {
upperChar = ConditionalSpecialCasing.toUpperCaseEx(this, i, locale);
} else {
upperChar = Character.toUpperCaseEx(srcChar);
}
if ((upperChar == Character.ERROR)
|| (upperChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
if (upperChar == Character.ERROR) {
if (localeDependent) {
upperCharArray =
ConditionalSpecialCasing.toUpperCaseCharArray(this, i, locale);
} else {
upperCharArray = Character.toUpperCaseCharArray(srcChar);
}
} else if (srcCount == 2) {
resultOffset += Character.toChars(upperChar, result, i + resultOffset) - srcCount;
continue;
} else {
upperCharArray = Character.toChars(upperChar);
}
/* Grow result if needed */
int mapLen = upperCharArray.length;
if (mapLen > srcCount) {
char[] result2 = new char[result.length + mapLen - srcCount];
System.arraycopy(result, 0, result2, 0, i + resultOffset);
result = result2;
}
for (int x = 0; x < mapLen; ++x) {
result[i + resultOffset + x] = upperCharArray[x];
}
resultOffset += (mapLen - srcCount);
} else {
result[i + resultOffset] = (char)upperChar;
}
}
return new String(result, 0, len + resultOffset);
}
toLowerCase()
public String toLowerCase(Locale locale) {
if (locale == null) {
throw new NullPointerException();
}
int firstUpper;
final int len = value.length;
/* Now check if there are any characters that need to be changed. */
scan: {
for (firstUpper = 0 ; firstUpper < len; ) {
char c = value[firstUpper];
if ((c >= Character.MIN_HIGH_SURROGATE)
&& (c <= Character.MAX_HIGH_SURROGATE)) {
int supplChar = codePointAt(firstUpper);
if (supplChar != Character.toLowerCase(supplChar)) {
break scan;
}
firstUpper += Character.charCount(supplChar);
} else {
if (c != Character.toLowerCase(c)) {
break scan;
}
firstUpper++;
}
}
return this;
}
char[] result = new char[len];
int resultOffset = 0; /* result may grow, so i+resultOffset
* is the write location in result */
/* Just copy the first few lowerCase characters. */
System.arraycopy(value, 0, result, 0, firstUpper);
String lang = locale.getLanguage();
boolean localeDependent =
(lang == "tr" || lang == "az" || lang == "lt");
char[] lowerCharArray;
int lowerChar;
int srcChar;
int srcCount;
for (int i = firstUpper; i < len; i += srcCount) {
srcChar = (int)value[i];
if ((char)srcChar >= Character.MIN_HIGH_SURROGATE
&& (char)srcChar <= Character.MAX_HIGH_SURROGATE) {
srcChar = codePointAt(i);
srcCount = Character.charCount(srcChar);
} else {
srcCount = 1;
}
if (localeDependent ||
srcChar == '\u03A3' || // GREEK CAPITAL LETTER SIGMA
srcChar == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE
lowerChar = ConditionalSpecialCasing.toLowerCaseEx(this, i, locale);
} else {
lowerChar = Character.toLowerCase(srcChar);
}
if ((lowerChar == Character.ERROR)
|| (lowerChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
if (lowerChar == Character.ERROR) {
lowerCharArray =
ConditionalSpecialCasing.toLowerCaseCharArray(this, i, locale);
} else if (srcCount == 2) {
resultOffset += Character.toChars(lowerChar, result, i + resultOffset) - srcCount;
continue;
} else {
lowerCharArray = Character.toChars(lowerChar);
}
/* Grow result if needed */
int mapLen = lowerCharArray.length;
if (mapLen > srcCount) {
char[] result2 = new char[result.length + mapLen - srcCount];
System.arraycopy(result, 0, result2, 0, i + resultOffset);
result = result2;
}
for (int x = 0; x < mapLen; ++x) {
result[i + resultOffset + x] = lowerCharArray[x];
}
resultOffset += (mapLen - srcCount);
} else {
result[i + resultOffset] = (char)lowerChar;
}
}
return new String(result, 0, len + resultOffset);
}
toString()
public String toString() {
return this;
}
valueOf()
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
其他
trim()
public String trim() {
int len = value.length;
int st = 0;
char[] val = value; /* avoid getfield opcode */
while ((st < len) && (val[st] <= ' ')) {
st++;
}
while ((st < len) && (val[len - 1] <= ' ')) {
len--;
}
return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
}
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;
}
emmmm,这里放上一个解释
Java编程:String 类中 hashCode() 方法详解
isEmpty()
public boolean isEmpty() {
return value.length == 0;
}
如果长度为0 即为空o
length()
public int length() {
return value.length;
}