http://doc.java.sun.com/DocWeb/api/all/java.lang.String
下文转自:http://blog.csdn.net/liqj2ee/article/details/581243
package java.lang;
import java.io.ObjectStreamClass;
import java.io.ObjectStreamField;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
/**
*
* 此类表示字符串,他是一个final的类,它的值不可改变(immutable)因而是线程安全的,
* 它内部有个char数组,所有操作都是基于此数组
*
* 在操作参数有一个是字符串的情况下"+"表示字符串链接,如果其中一个参数是对象
* 则调用此对象的toString方法得到表示此对象的字符串,例如我们可以使用令一种
* 方式(并非直接调用toString方法)获得对象的字符串表示: obj + "";(但效率不好)
*
* 在做有改变的操作时,String会返回一个满足条件的新的字符串,而不改变自身,所以在
* 做连接等改变操作时使用StringBuffer效率会更好,例如我们做两个字符串的连接,String
* 会生成一个新的大数组将数据拷贝过去,然后例用数组生成一个新的String对象,而使用
* StringBuffer是在做append时如果连接后的长度没有超出其内部的char数组则直接
* 加入到数组中,如果过大才创建新的大数组,因为大多情况不会超过范围所以做重建数组,并
* 拷贝的操作要比String少(String每次都做),所以效率会高
*
* 常量的字符串会被默认池化,也就是说他们公用同一个对象(内存地址相同)
* 例如:
* String aa = "aa";
* String bb = new String("aa");
* aa == "aa"相等
* bb == "aa"不等
* bb.inter() == "aa"相等
*
* comment by liqiang
*
* @author Lee Boynton
* @author Arthur van Hoff
*
*/
public final class String
implements java.io.Serializable, Comparable, CharSequence
{
//存放此字符串中所含数据的数组,注意它不一定是从0位置存储的,
//也就是说它可能包含冗余数据
private char value[];
//字符串数据在数组中的存放位置的起始点
private int offset;
//字符串数据的长度(注意不是数据数组的长度)
private int count;
//缓存的hashCode
private int hash = 0;
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
/**
* Class String is special cased within the Serialization Stream Protocol.
*
* A String instance is written intially into an ObjectOutputStream in the
* following format:
* <pre>
* <code>TC_STRING</code> (utf String)
* </pre>
* The String is written by method <code>DataOutput.writeUTF</code>.
* A new handle is generated to refer to all future references to the
* string instance within the stream.
*/
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
/**
*
* 构造函数,初始化为一个空字符串
*
*/
public String() {
//创建一个空的char数组
value = new char[0];
}
/**
*
* 构造函数,通过字符串构造一个新字符串
*
*/
public String(String original) {
//取得源数据的长度
this.count = original.count;
if (original.value.length > this.count) {
//如果源字符串的数组中有冗余数据,
//则生成一个长度为源字符串数据的有效长度的数组并将有效数据拷贝过去
this.value = new char[this.count];
System.arraycopy(original.value, original.offset,
this.value, 0, this.count);
} else {
//如果源字符串的数组中没有冗余数据则直接将源字符串的数组赋给新字符串对象
this.value = original.value;
}
}
/**
*
* 通过char数组中的数据构造一个新字符串对象
*
*/
public String(char value[]) {
//取得长度
this.count = value.length;
//创建一个同长度的新数组
this.value = new char[count];
//将数组中的数据拷贝到新数组中
System.arraycopy(value, 0, this.value, 0, count);
}
/**
*
* 通过char数组中的数据构造一个新字符串对象
*
* @param value 源数组
* @param offset 源数组的起始位置
* @param count 拷贝的数据长度
*
*/
public String(char value[], int offset, int count) {
if (offset < 0) {//起始位置小于0抛出异常
throw new StringIndexOutOfBoundsException(offset);
}
if (count < 0) {//拷贝长度小于0抛出异常
throw new StringIndexOutOfBoundsException(count);
}
//offset + count > value.length比较好理解
//如果起始位置(偏移量)大于最大的起始位置,表示越界,抛出异常
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
//创建拷贝数据长度的新数组
this.value = new char[count];
//设置当前对象的数据长度
this.count = count;
//将源数组中的数据拷贝到新数组中
System.arraycopy(value, offset, this.value, 0, count);
}
/**
*
* 通过byte数组中的数据构造一个新字符串对象
*
* @param ascii 源byte数组
* @param hibyte 每个char高8位的数据,低8位为相应byte数组的值
* @param offset 偏移量
* @param count 拷贝长度
*
*/
public String(byte ascii[], int hibyte, int offset, int count) {
//检查是否越界
checkBounds(ascii, offset, count);
//身成拷贝个数长度的新char数组
char value[] = new char[count];
//设置当前对象的数据长度
this.count = count;
//将新生成的字符串赋给此对象的数组数组,这是数组中没有数据
this.value = value;
if (hibyte == 0) {
for (int i = count ; i-- > 0 ;) {
value[i] = (char) (ascii[i + offset] & 0xff);
}
} else {
//左移8位
hibyte <<= 8;
for (int i = count ; i-- > 0 ;) {
//用hibyte填充高位
value[i] = (char) (hibyte | (ascii[i + offset] & 0xff));
}
}
}
/**
*
* 通过byte数组中的数据构造一个新字符串对象
*
*/
public String(byte ascii[], int hibyte) {
this(ascii, hibyte, 0, ascii.length);
}
/*
*
* 检查操作是否越界
*
*/
private static void checkBounds(byte[] bytes, int offset, int length) {
if (length < 0)//拷贝长度小于0抛出异常
throw new StringIndexOutOfBoundsException(length);
if (offset < 0)//起始位置小于0抛出异常
throw new StringIndexOutOfBoundsException(offset);
if (offset > bytes.length - length)//起始位置大于最大起始位置抛出异常
throw new StringIndexOutOfBoundsException(offset + length);
}
/**
*
* 通过byte数组中的数据,和编码方式,构造一个新字符串对象
*
*/
public String(byte bytes[], int offset, int length, String charsetName)
throws UnsupportedEncodingException
{
//编码形式位空则抛出异常
if (charsetName == null)
throw new NullPointerException("charsetName");
//检查边界
checkBounds(bytes, offset, length);
//编码转化
value = StringCoding.decode(charsetName, bytes, offset, length);
count = value.length;
}
/**
*
* 通过byte数组中的数据,和编码方式,构造一个新字符串对象
*
*/
public String(byte bytes[], String charsetName)
throws UnsupportedEncodingException
{
this(bytes, 0, bytes.length, charsetName);
}
/**
*
* 通过byte数组中的数据构造一个新字符串对象
*
*/
public String(byte bytes[], int offset, int length) {
checkBounds(bytes, offset, length);
value = StringCoding.decode(bytes, offset, length);
count = value.length;
}
/**
*
* 通过byte数组中的数据构造一个新字符串对象
*
*/
public String(byte bytes[]) {
this(bytes, 0, bytes.length);
}
/**
*
* 通过StringBuffer构造一个新字符串对象
*
*/
public String (StringBuffer buffer) {
synchronized(buffer) {
//这是一个包内的方法,
//如果设置为Shared形式getVlaue得到是StringBuffer的内部数据的拷贝
buffer.setShared();
//取得StringBuffer的内部数据
this.value = buffer.getValue();
//设置起始位置为0
this.offset = 0;
//设置单前对象所和所数据长度
this.count = buffer.length();
}
}
//包内的构造函数
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
/**
*
* 返回字符串长度
*
*/
public int length() {
return count;
}
/**
*
* 返回指定位置的字符
*
*/
public char charAt(int index) {
//index超出范围则抛出异常
if ((index < 0) || (index >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
//返回数组中的元素,注意加上偏移量才是数组中的真实位置
return value[index + offset];
}
/**
*
* 拷贝字符串数的一段数据到目标char数组中
*
* @param srcBegin 拷贝的起始位置,注意他是以偏移位置为基准的,不是以数组的0位置
* 此类变量可以按逻辑位置来考虑(相对于String数据的第一个字符的位置)
* @param srcEnd 拷贝数据结束位置的后一个位置,逻辑位置
* @param dst 目标数组
* @param dstBegin 目标数组的起始位置
*
*/
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);
}
//将指定段数据拷贝到目标数组中
System.arraycopy(value, offset + srcBegin, dst, dstBegin,
srcEnd - srcBegin);
}
/**
*
* 拷贝字符串数的一段数据到目标byte数组中
* 拷贝时将每个char转成byte
*
* @param srcBegin 拷贝的起始位置,逻辑位置
* @param srcEnd 拷贝数据结束位置的后一个位置,逻辑位置
* @param dst 目标数组
* @param dstBegin 目标数组的起始位置
*
*/
public void getBytes(int srcBegin, int srcEnd, byte 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);
}
//目标数组的起始位置
int j = dstBegin;
int n = offset + srcEnd;
int i = offset + srcBegin;
char[] val = value; /* avoid getfield opcode */
//将当前数组中的指定段数据拷贝到byte数组中
while (i < n) {
//将char转程btye
dst[j++] = (byte)val[i++];
}
}
/**
*
* 按charsetName的编码方式编码成byte数组
* 如果不能使用默认的编码方式编码则使用此方法用特定的编码方式
*
*/
public byte[] getBytes(String charsetName)
throws UnsupportedEncodingException
{
return StringCoding.encode(charsetName, value, offset, count);
}
/**
*
* 使用默认的编码方式编码
*
*/
public byte[] getBytes() {
return StringCoding.encode(value, offset, count);
}
/**
*
* 判断指定对象是否于当前字符串对象相等
*
*/
public boolean equals(Object anObject) {
//如果练个对象表示同一对象直接返回true
if (this == anObject) {
return true;
}
//如果指定对象是String类型进行下一步判断
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) {
//有一个不等的则直接返回false
if (v1[i++] != v2[j++])
return false;
}
//数据都相等返回true
return true;
}
}
return false;
}
/**
*
* 判断当前字符串的内容是否跟指定的
* StringBuffer对象的内容相等
*
*/
public boolean contentEquals(StringBuffer sb) {
synchronized(sb) {
//判断数据长度是否相等
if (count != sb.length())
return false;
//循环判断两个对象的内部char数组的每个元素
char v1[] = value;
char v2[] = sb.getValue();
int i = offset;
int j = 0;
int n = count;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
}
//如果内容都相等则返回true
return true;
}
/**
*
* 判断两个字符串是否相等,不区分大小写
*
*/
public boolean equalsIgnoreCase(String anotherString) {
return (this == anotherString) ? true :
(anotherString != null) && (anotherString.count == count) &&
regionMatches(true, 0, anotherString, 0, count);
}
/**
*
* 比较两个字符串,如果有不等的字符串,则返回第一出现不匹配的字符串只差
* 如果没有不等的字符串则返回两个字符串的字符数差(可能会有短的字符串与
* 大字符串的前部分完全相等,则返回他们的字符串长度差),
* 小于返回负数,相等返回0,大于返回正数
*
*/
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) {//循环最多n次
char c1 = v1[i++];
char c2 = v2[j++];
//如果两个字符不等返回他们的差
if (c1 != c2) {
return c1 - c2;
}
}
}
//n(最小数据长度)个长度数据段都相等,返回两个字符串的字符数的大小差
return len1 - len2;
}
/**
*
* 比较两个对象,小于返回负数,相等返回0,大于返回正数
* 如果指定的对象不是String类型抛出ClassCastException
*
*/
public int compareTo(Object o) {
return compareTo((String)o);
}
/**
*
* CaseInsensitiveComparator对象,用来做不计大小写的比较操作
*
*/
public static final Comparator CASE_INSENSITIVE_ORDER
= new CaseInsensitiveComparator();
//静态内部类用来做不计大小写的比较操作
private static class CaseInsensitiveComparator
implements Comparator, java.io.Serializable {
private static final long serialVersionUID = 8575799808933029326L;
//必较方法
public int compare(Object o1, Object o2) {
//转型
String s1 = (String) o1;
String s2 = (String) o2;
//取得字符串长度
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;
}
}
/**
*
* 不区分大小写比较
*
*/
public int compareToIgnoreCase(String str) {
//调用CaseInsensitiveComparator对象的比较方法
return CASE_INSENSITIVE_ORDER.compare(this, str);
}
/**
*
* 比较两个字符串区域是否相等
*
*/
public boolean regionMatches(int toffset, String other, int ooffset,
int len) {
//取得两个字符串的数组数组和起始位置
char ta[] = value;
int to = offset + toffset;
char pa[] = other.value;
int po = other.offset + ooffset;
//范围不符直接返回false
if ((ooffset < 0) || (toffset < 0) || (toffset > (long)count - len)
|| (ooffset > (long)other.count - len)) {
return false;
}
//最大循环数为len
while (len-- > 0) {
//有不同的字符串返回false
if (ta[to++] != pa[po++]) {
return false;
}
}
//都符合返回true
return true;
}
/**
*
* 判断两个字符串区域是否相等
*
* @param ignoreCase true表示不区分大小写
* @param toffset 当前字符串判断的起始位置,逻辑位置
* @param other 比较的字符串
* @param ooffset 比较字符串判断的起始位置
* @param len 比较区域的长度
*
*/
public boolean regionMatches(boolean ignoreCase, int toffset,
String other, int ooffset, int len) {
//取得当前的数据数组
char ta[] = value;
//计算出物理起始位置
int to = offset + toffset;
//得到比较数组的数据数组
char pa[] = other.value;
//比较数组的物理起始位置
int po = other.offset + ooffset;
//范围不符直接返回false
if ((ooffset < 0) || (toffset < 0) || (toffset > (long)count - len) ||
(ooffset > (long)other.count - len)) {
return false;
}
while (len-- > 0) {//最大循环len次
//得到起始位置的字符
char c1 = ta[to++];
char c2 = pa[po++];
//得到第一个不相等的位置
if (c1 == c2) {
continue;
}
//区分大小写则直接返回false,
//不区分则进行下面的判断
if (ignoreCase) {
//将自字符串装为大写比较
char u1 = Character.toUpperCase(c1);
char u2 = Character.toUpperCase(c2);
if (u1 == u2) {
//如果相等继续
continue;
}
//因为转成大写不能很好的处理Georgian字母表,则转成小写在做判断
if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
//如果相等继续
continue;
}
}
return false;
}
return true;
}
/**
*
* 从toffset位置开始判断当前字段串是否以prefix开头
*
*/
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;
//范围不符
if ((toffset < 0) || (toffset > count - pc)) {
return false;
}
while (--pc >= 0) {
//有不等的字符返回false
if (ta[to++] != pa[po++]) {
return false;
}
}
//全相等返回true
return true;
}
/**
*
* 判断当前字段串是否以prefix开头
*
*/
public boolean startsWith(String prefix) {
return startsWith(prefix, 0);
}
/**
*
* 判断当前字段串是否以suffix结尾
*
*/
public boolean endsWith(String suffix) {
return startsWith(suffix, count - suffix.count);
}
/**
*
* 得出hashCode值
* 算法是:
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
*
*/
public int hashCode() {
//取得缓存的hashCode
int h = hash;
//如果缓存的hashCode为0(未被设置),则计算hashCode
if (h == 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;
}
/**
*
* 从开始位置开始向后查找指定字符的位置,如果查不到返回-1
*
*/
public int indexOf(int ch) {
return indexOf(ch, 0);
}
/**
*
* 从指定位置开始向后查找指定字符的位置,如果查不到返回-1
*
* @param ch 要查找的字符
* @param fromIndex 在字符串中向后查找的起始位置,逻辑位置
* @return 查找到返回位标,没有查到返回-1
*
*/
public int indexOf(int ch, int fromIndex) {
//最后的位置,不包括
int max = offset + count;
char v[] = value;
if (fromIndex < 0) {
//其实位置小于0设置为0
fromIndex = 0;
} else if (fromIndex >= count) {
// Note: fromIndex might be near -1>>>1.
//超出范围返回-1(表示没有查找到)
return -1;
}
//循环查找此字符
for (int i = offset + fromIndex ; i < max ; i++) {
if (v[i] == ch) {
//返回查找到的逻辑位置
return i - offset;
}
}
//没有查找到返回-1
return -1;
}
/**
*
* 返回最后位置向前查找的指定字符的位置
*
*/
public int lastIndexOf(int ch) {
return lastIndexOf(ch, count - 1);
}
/**
*
* 返回末尾位置向前查找的指定字符的位置
*
* @param ch 要查找的字符
* @param fromIndex 在字符串中向前查找的起始位置,逻辑位置
* @return 查找到返回位标,没有查到返回-1
*
*/
public int lastIndexOf(int ch, int fromIndex) {
int min = offset;
char v[] = value;
//循环查找,从后往前,fromIndex小于0没有经过循环体直接返回-1
for (int i = offset + ((fromIndex >= count) ? count - 1 : fromIndex) ; i >= min ; i--) {
if (v[i] == ch) {
//找到则返回字符所在的位置
return i - offset;
}
}
//没有找到则返回-1
return -1;
}
/**
*
* 从起始位置查找指定字符串的位置,不存在返回-1
*
*/
public int indexOf(String str) {
return indexOf(str, 0);
}
/**
*
* 从指定位置查找指定字符串的位置,不存在返回-1
*
*/
public int indexOf(String str, int fromIndex) {
return indexOf(value, offset, count,
str.value, str.offset, str.count, fromIndex);
}
/**
*
* 指定数组段的数组在源数组中从fromIndex向后查找的位置
*
* @param source 源字符数组(被查找字符数组)
* @param sourceOffset 源字符数组有效数据的起始位置
* @param sourceCount 源字符数组的有效数据长度
* @param target 查找字符数组
* @param targetOffset 查找字符数组有效数据的起始位置
* @param targetCount 查找字符串的有效数据长度
* @param fromIndex 在源字符数组查找的起始位置,逻辑位置
*
*/
static int indexOf(char[] source, int sourceOffset, int sourceCount,
char[] target, int targetOffset, int targetCount,
int fromIndex) {
if (fromIndex >= sourceCount) {
//起始位置(逻辑位置,)
//超过数组的有效数据(sourceOffset到sourceOffset+sourceCount-1)的长度,
//如果查找数组的有效数据长度为0,则返回源数组有效位的后一位(它是无效的),否则返回-1
return (targetCount == 0 ? sourceCount : -1);
}
//如果起始位置小于0,则从0开始
if (fromIndex < 0) {
fromIndex = 0;
}
if (targetCount == 0) {
return fromIndex;
}
//查找数组的起始位置
char first = target[targetOffset];
//源数组的起始位置
int i = sourceOffset + fromIndex;
//源数组的最后查找位置,包括,因为要保证有效位置至少要有targetCount个字符
int max = sourceOffset + (sourceCount - targetCount);
startSearchForFirstChar:
while (true) {
//循环直到找到源数组中与查找数组第一个位置相等的字符,或超出范围
while (i <= max && source[i] != first) {
i++;
}
//如果没有相等的则返回-1
if (i > max) {
return -1;
}
/* Found first character, now look at the rest of v2 */
//比较从i位置开始的后续targetCount长度的字符是否与比较字符段相等
//相等则返回查找到的逻辑位置,否则退出循环,退出到的是顶层
//因为i位置已经相等,从它的下个位置比较
int j = i + 1;
//比较的最后位置,不包括
int end = j + targetCount - 1;
//标记数组的第二个字符位置
int k = targetOffset + 1;
//循环比较后续字符
while (j < end) {
if (source[j++] != target[k++]) {
//如果有不等的则使源数组中的下次比较位置的起点加1
//退出循环,注意这里使用了标签,可以退出到标签标记的循环层
//这里退出到顶层,如果没有用标签,只是简单的continue只能退出本层混还
i++;
continue startSearchForFirstChar;
}
}
//如果找到此字符段,则返回起始位置的逻辑位标
return i - sourceOffset;
}
}
/**
*
* 从末尾位置开始向前查找指定字符串
*
*/
public int lastIndexOf(String str) {
return lastIndexOf(str, count);
}
/**
*
* 从指定位置开始向前查找指定字符串
*
*/
public int lastIndexOf(String str, int fromIndex) {
return lastIndexOf(value, offset, count,
str.value, str.offset, str.count, fromIndex);
}
/**
*
* 从指定位置开始向前查找指定字符段的位置
*
* @param source the characters being searched.
* @param sourceOffset offset of the source string.
* @param sourceCount count of the source string.
* @param target the characters being searched for.
* @param targetOffset offset of the target string.
* @param targetCount count of the target string.
* @param fromIndex the index to begin searching from.
*/
static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
char[] target, int targetOffset, int targetCount,
int fromIndex) {
//最大的起始位置,逻辑位置(如果sourceCount为6,targetCount为2,则差为4,但是是从0开始的
//所以它表示的是5的位置,所以正好是最后一个查找位置,注意个数,与位标这两个概念)
int rightIndex = sourceCount - targetCount;
if (fromIndex < 0) {
//起始位置小于0返回没有找到
return -1;
}
//起始位置大于最大起始位置,设置成最大起始位置
if (fromIndex > rightIndex) {
fromIndex = rightIndex;
}
//如果查找的是空串,直接返回起始位置
if (targetCount == 0) {
return fromIndex;
}
//查找字符段的最后有效位置
int strLastIndex = targetOffset + targetCount - 1;
//查找字符段的最后一个字符
char strLastChar = target[strLastIndex];
//末尾在左边的最小值,极限情况,保证左边要有targetCount个字符在前面
int min = sourceOffset + targetCount - 1;
//从右面查找的最右位置,可以理解为sourceOffset+fromIndex+(targetCount - 1)
//得到了一个范围,都是右边的位标,i(大)到min(小)
int i = min + fromIndex;
startSearchForLastChar:
//从指定位置向左判断匹配位置,
//每次数据段的比较是从后到前的循环,但计算出的位置是最左边的
while (true) {
//找到与查找字符数组最后一个元素相等的字符,或范围超出min
while (i >= min && source[i] != strLastChar) {
i--;
}
//没有相等的字符则直接返回-1
if (i < min) {
return -1;
}
int j = i - 1;
//从右边开始最后一个判断字符位置,不包括,
//也是计算出的从左边开始的起始位置的前一个位置
int start = j - (targetCount - 1);
int k = strLastIndex - 1;
//从后往前比较,(循环次数最多为targetCount - 1),从i-1到i-targetCount
//用的是位标做判断,而不是用个数
while (j > start) {
if (source[j--] != target[k--]) {
i--;
continue startSearchForLastChar;
}
}
//查找到,返回位标
//返回的是从左开始算的位标
return start - sourceOffset + 1;
}
}
/**
*
* 取得从beginIndex位置开始到最后位置的子字符串
*
*/
public String substring(int beginIndex) {
return substring(beginIndex, count);
}
/**
*
* 取得指定区域的字符串
*
* @param beginIndex 起始位置,包括
* @param endIndex 结束位置,不包括
*
*/
public String substring(int beginIndex, int endIndex) {
//超出范围抛出异常
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > count) {
throw new StringIndexOutOfBoundsException(endIndex);
}
if (beginIndex > endIndex) {
throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
}
//利用原数据和新位置,生成字符串对象,只是改变了起始位置和长度,并没有生成新的数组
//为了提高效率
return ((beginIndex == 0) && (endIndex == count)) ? this :
new String(offset + beginIndex, endIndex - beginIndex, value);
}
/**
*
* 返回子序列
*
*/
public CharSequence subSequence(int beginIndex, int endIndex) {
return this.substring(beginIndex, endIndex);
}
/**
*
* 连接字符串.str将加到末尾
*
*/
public String concat(String str) {
//取得连接的字符串
int otherLen = str.length();
if (otherLen == 0) {
//如过连接字符串长度为0则直接返回当前对象
return this;
}
//生成新的大长度数组
char buf[] = new char[count + otherLen];
//将当前对象的数据考到新数组中,从0开始
getChars(0, count, buf, 0);
//将连接字符串中的字符拷贝到新数组中,
//从count开始,达到连接到当前字符串后面的效果
str.getChars(0, otherLen, buf, count);
//利用新生成的数组生成新字符串
return new String(0, count + otherLen, buf);
}
/**
*
* 将字符串中的所有oldChar字符替换为newChar字符
*
*/
public String replace(char oldChar, char newChar) {
if (oldChar != newChar) {
int len = count;
int i = -1;
char[] val = value; /* avoid getfield opcode */
int off = offset; /* avoid getfield opcode */
//取得第一个与新字符相等的位置
while (++i < len) {
if (val[off + i] == oldChar) {
break;
}
}
if (i < len) {//没有超出范围
//生成新数组,并将前面不同的字符段拷贝过去
char buf[] = new char[len];
for (int j = 0 ; j < i ; j++) {
buf[j] = val[off+j];
}
//对后面的字符段做循环,如果是需要替换字符,将替换
//字符拷贝到数组中,如果不是则将原数组中的字符拷贝到新数组
while (i < len) {
char c = val[off + i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
//通过新数组生成新字符串
return new String(0, len, buf);
}
}
//如果新字符与旧字符相等则直接返回当前对象
return this;
}
/**
*
* 返回当前字符串是构与正则表达式regex匹配
*
*/
public boolean matches(String regex) {
return Pattern.matches(regex, this);
}
/**
*
* 将此字符串中第一个匹配正则表达式的子串替换为replacement
*
*/
public String replaceFirst(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
}
/**
*
* 将此字符串中所有匹配正则表达式的子串替换为replacement
*
*/
public String replaceAll(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
/**
*
*/
public String[] split(String regex, int limit) {
return Pattern.compile(regex).split(this, limit);
}
/**
*
* 通过指定的正则表达式拆分字符串
*
*/
public String[] split(String regex) {
return split(regex, 0);
}
/**
*
* 将字符串转为小写
* Locale只在表示土耳其的时候有意义
*
*/
public String toLowerCase(Locale locale) {
//如果locale为null抛出异常
if (locale == null)
throw new NullPointerException();
int len = count;
int off = offset;
char[] val = value;
int firstUpper;
//这个标签和块的使用没有意义
scan: {
//按逻辑位置循环
for (firstUpper = 0 ; firstUpper < len ; firstUpper++) {
char c = value[off+firstUpper];
//如果不是小写则终止循环
if (c != Character.toLowerCase(c)) {break scan;}
}
//如果都是小写的直接返回
return this;
}
//生成新的数组,用于生成新字符串
char[] result = new char[count];
//将前面连续小写部分拷贝到新建字符数组中
System.arraycopy(val, off, result, 0, firstUpper);
//处理从有需要处理字符开始后面的部分
if (locale.getLanguage().equals("tr")) {
//土耳其的特殊处理
for (int i = firstUpper; i < len; ++i) {
char ch = val[off+i];
//特殊字符特殊处理
if (ch == 'I') {
result[i] = '/u0131';
continue;
}
if (ch == '/u0130') {
result[i] = 'i';
continue;
}
//非特殊字符直接转换
result[i] = Character.toLowerCase(ch);
}
} else {
//非土耳其的Locale直接转为小写
for (int i = firstUpper; i < len; ++i) {
//无论此方法
result[i] = Character.toLowerCase(val[off+i]);
}
}
//通过新生成的数组生成字符串
return new String(0, result.length, result);
}
/**
*
* 将当前字符串转成小写
*
*/
public String toLowerCase() {
//使用默认的Local
return toLowerCase(Locale.getDefault());
}
/**
*
* 将字符串转为大写
* Locale只在表示土耳其的时候有意义
*
*/
public String toUpperCase(Locale locale) {
int len = count;
int off = offset;
char[] val = value;
int firstLower;
//定位到第一个需要处理的字符位置上
scan: {
char upperCaseChar;
char c;
for (firstLower = 0 ; firstLower < len ; firstLower++) {
c = value[off+firstLower];
upperCaseChar = Character.toUpperCaseEx(c);
//如果字符为'/uFFFF',或不是大写则返回
if (upperCaseChar == Character.CHAR_ERROR || c != upperCaseChar) {
break scan;
}
}
//都为大写直接返回
return this;
}
//创建新数组,可能变大
char[] result = new char[len];
int resultOffset = 0; /* result grows, so i+resultOffset
* is the write location in result */
//将前面连续大写部分拷贝到新生成数组
System.arraycopy(val, off, result, 0, firstLower);
if (locale.getLanguage().equals("tr")) {//土耳其
char[] upperCharArray;
char upperChar;
char ch;
for (int i = firstLower; i < len; ++i) {
ch = val[off+i];
//特殊字符处理
if (ch == 'i') {
result[i+resultOffset] = '/u0130'; // dotted cap i
continue;
}
if (ch == '/u0131') { // dotless i
result[i+resultOffset] = 'I'; // cap I
continue;
}
//转为大写
upperChar = Character.toUpperCaseEx(ch);
if (upperChar == Character.CHAR_ERROR) {//'/uFFFF'情况
upperCharArray = Character.toUpperCaseCharArray(ch);
int mapLen = upperCharArray.length;
char[] result2 = new char[result.length + mapLen - 1];
//将已处理过的拷贝过去
System.arraycopy(result, 0, result2, 0,
i + 1 + resultOffset);
for (int x=0; x<mapLen; ++x) {
result2[i+resultOffset++] = upperCharArray[x];
}
--resultOffset;
result = result2;
}
else {
//非'/uFFFF'情况赋给相应位置
result[i+resultOffset] = upperChar;
}
}
} else {//一般情况(非土耳其)
char[] upperCharArray;
char upperChar;
char ch;
for (int i = firstLower; i < len; ++i) {
ch = val[off+i];
//转成大写
upperChar = Character.toUpperCaseEx(ch);
if (upperChar == Character.CHAR_ERROR) {//'/uFFFF'情况
upperCharArray = Character.toUpperCaseCharArray(ch);
int mapLen = upperCharArray.length;
char[] result2 = new char[result.length + mapLen - 1];
//将已处理过的拷贝过去
System.arraycopy(result, 0, result2, 0,
i + 1 + resultOffset);
for (int x=0; x<mapLen; ++x) {
result2[i+resultOffset++] = upperCharArray[x];
}
--resultOffset;
result = result2;
}
else {
//非'/uFFFF'情况赋给相应位置
result[i+resultOffset] = upperChar;
}
}
}
//通过新数组生成字符串
return new String(0, result.length, result);
}
/**
*
* 将当前字符串转成大写形式
*
*/
public String toUpperCase() {
//使用默认的Local
return toUpperCase(Locale.getDefault());
}
/**
*
* 清楚字符串前后的连续空格
*
*/
public String trim() {
int len = count;
int st = 0;
int off = offset;
char[] val = value;
while ((st < len) && (val[off + st] <= ' ')) {
//取得前面第一个非空格的位置
st++;
}
while ((st < len) && (val[off + len - 1] <= ' ')) {
//取得后面第一个非空格的位置
len--;
}
//如果有空格则截取中间部分,
//起点是前面第一个非空格位置,重点是后面第一个非空格位置
return ((st > 0) || (len < count)) ? substring(st, len) : this;
}
/**
*
* 当前对象的字符串表示,直接返回当前对象
*
*/
public String toString() {
return this;
}
/**
*
* 返回当前字符串数据的拷贝
*
*/
public char[] toCharArray() {
//生成新数组
char result[] = new char[count];
//将当前数据拷贝到新数组中
getChars(0, count, result, 0);
return result;
}
/**
*
* 取得对象的字符串表示
*
*/
public static String valueOf(Object obj) {
//如果对象为null则返回"null"字符串,否则调用相应对象的toString方法
return (obj == null) ? "null" : obj.toString();
}
/**
*
* 显示char数组所对应的字符串
*
*/
public static String valueOf(char data[]) {
//通过数组身成新的字符串
return new String(data);
}
/**
*
* 显示char数组指定区域所对应的字符串
*
*/
public static String valueOf(char data[], int offset, int count) {
return new String(data, offset, count);
}
/**
*
* 通过拷贝数组中指定部分的数据,生成一个新字符串
*
*/
public static String copyValueOf(char data[], int offset, int count) {
// All public String constructors now copy the data.
return new String(data, offset, count);
}
/**
*
* 通过拷贝数组中的数据,生成一个新字符串
*
*/
public static String copyValueOf(char data[]) {
return copyValueOf(data, 0, data.length);
}
/**
*
* boolean的字符串表示
*
*/
public static String valueOf(boolean b) {
return b ? "true" : "false";
}
/**
*
* char的字符串表示
*
*/
public static String valueOf(char c) {
//通过此char生成一个字符串
char data[] = {c};
return new String(0, 1, data);
}
/**
*
* int的字符串表示
*
*/
public static String valueOf(int i) {
return Integer.toString(i, 10);
}
/**
*
* long的字符串表示
*
*/
public static String valueOf(long l) {
return Long.toString(l, 10);
}
/**
*
* float的字符串表示
*
*/
public static String valueOf(float f) {
return Float.toString(f);
}
/**
*
* double的字符串表示
*
*/
public static String valueOf(double d) {
return Double.toString(d);
}
/**
*
* 返回一个从共享池中取出的String对象的本地方法
* 如果当前池中没有与当前对象的值相等(equals相等不是"=="相等)的字符串
* 则将当前对象加入,否则则取出池中的对象,常量字符串被默认加入池中
*
* String aa = "aa";
* String bb = new String("aa");
*
* bb == aa (false)
* bb.intern() == aa (true);
*
*/
public native String intern();
}