25
//与24类似,这不过
public byte[] getBytes(Charset charset) {
if (charset == null) throw new NullPointerException();
return StringCoding.encode(charset, value, 0, value.length);①
}
①
static byte[] encode(Charset cs, char[] ca, int off, int len) {
CharsetEncoder ce = cs.newEncoder();
int en = scale(len, ce.maxBytesPerChar());//获取可能达到的最长长度
byte[] ba = new byte[en];//创建一个绝对不会超出长度的数组,这部方法其实在日常项目中也可应用
//好处,不需要该数组的自增功能 1:可以增加性能,少一步提升之后还要复制数组的操作
//2:节省空间,自增后可能出现多余的空间根本用不到
if (len == 0)
return ba;//如果长度为0,就是空串,但是不会报错,没有转码的必要,直接返回
boolean isTrusted = false;
if (System.getSecurityManager() != null) {//检查系统安全管理器是否存在,有安全管理器在,这段要被转码
//的数据,可以降低被篡改的风险
if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {//判断是否被允许访问私有包
ca = Arrays.copyOfRange(ca, off, off + len);//如果安全管理器都没有,就不用判断是否允许了,执行可能会报错
off = 0;
}//这个复制的意义就是产生一个新的对象,防止因为该对象在其他的地方被用到了,发生了改变,产生的不可预知的情况
}
ce.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.reset();//之前见过的工厂类型的初始化对象
if (ce instanceof ArrayEncoder) {
int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
return safeTrim(ba, blen, cs, isTrusted);
//ArrayEncoder是一个接口,没有备注等解释。
//这应该是扩展的接口,如果字符集实现了这个接口,那么该接口提供的功能可以直接使用,不需要自己来实现
} else {
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca, off, len);//buffer可变长功能,wrap,构造缓冲区,对流的操作会更快
try {
CoderResult cr = ce.encode(cb, bb, true);//核心,最后的转码操作
//内部没啥可看的 主要是 cr = encodeLoop(in, out); 主要的实现放在更深的语言了,只能到此为止
if (!cr.isUnderflow())
cr.throwException();
cr = ce.flush(bb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
throw new Error(x);
}
return safeTrim(ba, bb.position(), cs, isTrusted);
//这步判断了一下前后的长度,如果长度一样,直接返回了,如果不一样就复制一下,生成新长度的数组返回
//结束
}
}
26:获取对象默认编码的byte
public byte[] getBytes(Charset charset) {
if (charset == null) throw new NullPointerException();
return StringCoding.encode(charset, value, 0, value.length);
}
static byte[] encode(char[] ca, int off, int len) {
String csn = Charset.defaultCharset().name();
try {
// use charset name encode() variant which provides caching.
return encode(csn, ca, off, len);//关于encode不再重复
} catch (UnsupportedEncodingException x) {
warnUnsupportedCharset(csn);
}
try {
return encode("ISO-8859-1", ca, off, len);
} catch (UnsupportedEncodingException x) {
// If this code is hit during VM initialization, MessageUtils is
// the only way we will be able to get any kind of error message.
MessageUtils.err("ISO-8859-1 charset not available: "
+ x.toString());
// If we can not find ISO-8859-1 (a required encoding) then things
// are seriously wrong with the installation.//翻译:未找到该字符集,安装严重错误
System.exit(1);//这个就厉害了,关掉虚拟机,而且是非正常关闭
return null;
}
}
//当给定的字符串并没有指定编码。就会使用iso
27最常用的比较
public boolean equals(Object anObject) {
if (this == anObject) {
return true;//如果hash值相同,就认为相同
}
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;
}
//其实没啥可说的,就是把字符串拆成字符数组,然后一个一个比较,
28
public boolean contentEquals(StringBuffer sb) {
synchronized (sb) {
return contentEquals((CharSequence) sb);
}
}
public boolean contentEquals(CharSequence cs) {
if (value.length != cs.length())//判断长度
return false;
// Argument is a StringBuffer, StringBuilder
if (cs instanceof AbstractStringBuilder) {//这是针对可变长字符串的。
char v1[] = value;
char v2[] = ((AbstractStringBuilder) cs).getValue();
int i = 0;
int n = value.length;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
// Argument is a String
if (cs.equals(this))判断hash是否相等
return true;
// Argument is a generic CharSequence
char v1[] = value;
int i = 0;
int n = value.length;
while (n-- != 0) {
if (v1[i] != cs.charAt(i))//这是继承CharSequence 通用的获取某个位置字符的方法
return false;
i++;
}
return true;
}
//虽然绕来绕去,但是其实和equals差不多
//CharSequence 是字符序列,
定义了四个实现
length();toString();subSequence();charAt()
subSequence()是返回的CharSequence 类型的 ,和subString功能一样
String重写了,可以只返回String
29,忽略大小写的对比
public boolean equalsIgnoreCase(String anotherString) {
return (this == anotherString) ? true
: (anotherString != null)
&& (anotherString.value.length == value.length)
&& regionMatches(true, 0, anotherString, 0, value.length);
}
30.比较大小
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;//一看就不是返回-1、0、1了。应该是不一样的那个字母的差值
}
k++;
}
return len1 - len2;
}
31.重写了一下comparator 的比较方法
public static final Comparator<String> CASE_INSENSITIVE_ORDER
= new CaseInsensitiveComparator();
private static class CaseInsensitiveComparator
implements Comparator<String>, java.io.Serializable {
// use serialVersionUID from JDK 1.2.2 for interoperability
private static final long serialVersionUID = 8575799808933029326L;
public int compare(String s1, String s2) {
int n1 = s1.length();
int n2 = s2.length();
int min = Math.min(n1, n2);
for (int i = 0; i < min; i++) {
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
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) {
// No overflow because of numeric promotion
return c1 - c2;
}
}
}
}
return n1 - n2;
}
}
32:调用上面那个方法,忽略大小写
public int compareToIgnoreCase(String str) {
return CASE_INSENSITIVE_ORDER.compare(this, str);
}
33:判断包含
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)//起点不能小于0,且不能大于长度
|| (toffset > (long)value.length - len)
|| (ooffset > (long)other.value.length - len)) {
return false;
}
while (len-- > 0) {//基于长度做while循环。
if (ta[to++] != pa[po++]) {//基于起点开始对每个字符进行比较。
return false;
}
}
return true;
}
tooffset:被比较的字符串的起点
other:要比较的字符串
ooffset:要比较的字符串的起点
len比较的长度
34:忽略大小写的比较,都是很熟悉的逻辑。
public boolean regionMatches(boolean ignoreCase, 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) {
char c1 = ta[to++];
char c2 = pa[po++];
if (c1 == c2) {
continue;
}
if (ignoreCase) {
char u1 = Character.toUpperCase(c1);
char u2 = Character.toUpperCase(c2);
if (u1 == u2) {
continue;
}
if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
continue;
}
}
return false;
}
return true;
}
有点重复,个人感觉可以和33合成一个
35:
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;
}
36:默认从第一个开始比较,调用35
public boolean startsWith(String prefix) {
return startsWith(prefix, 0);
}
37,判断结尾处有没有,也是调用的35
public boolean endsWith(String suffix) {//起点为被比较长度,减去比较的长度
return startsWith(suffix, value.length - suffix.value.length);
}
38:获取字符串的哈希值
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {//如果是同一个String对象调用此方法,不会重复计算
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];//String类型的hash算法
}
hash = h;
}
return h;
}
39:indexOf,返回输入第一次出现的位置
参数可以使int类型,也可以是String类型
首先是int类型
public int indexOf(int ch) {
return indexOf(ch, 0);
}
public int indexOf(int ch, int fromIndex) {
final int max = value.length;
if (fromIndex < 0) {
fromIndex = 0;
} else if (fromIndex >= max) {
return -1;
}
//没什么内容,基本都是一看就懂。
if (ch < Character.MIN_SUPPLEMENTARY_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);
}
}
关于int类型参数其实还是很坑的,搞不好会出错
String iString = new String(new char[]{2,1,3});
System.out.println(iString.indexOf(1));
System.out.println(iString);
//只有这样才会输出是1,代表找到了位置
//下面这种形式是找不到的,因为int类型与字符类型不同
String iString = new String(new char[]{'2','1','3'});
System.out.println(iString.indexOf(1));
System.out.println("213".indexOf(1));
//但是第一种方式,控制台输出是乱码,是无法正常使用的
//所以indexOf当参数为int类型时,很有可能达不到预期的效果
//下面另一种用法
String iString = new String(new char[]{2,1,3});
char c = 1;
System.out.println(iString.indexOf(c));
//这个方法如果是正常项目中还是很少见的,基本用不到。
char c = 97;
System.out.println(c);//a
String i = "2a3";
System.out.println(i.indexOf(c));//1
下面是源码
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) {//把字符与int类型进行比较
return i;
}
}
return -1;
} else {
return indexOfSupplementary(ch, fromIndex);
}
}
接下来是参数为String的查找第一处的源码
public int indexOf(String str) {
return indexOf(str, 0);
}
public int indexOf(String str, int fromIndex) {
return indexOf(value, 0, value.length,
str.value, 0, str.value.length, 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) {
return (targetCount == 0 ? sourceCount : -1);
}
if (fromIndex < 0) {
fromIndex = 0;
}
if (targetCount == 0) {
return fromIndex;
}
char first = target[targetOffset];
int max = sourceOffset + (sourceCount - targetCount);//这一步就没看懂
//因为测试没达到预期的效果,逻辑就不看了
for (int i = sourceOffset + fromIndex; i <= max; i++) {
if (source[i] != first) {
while (++i <= max && source[i] != first);
}
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) {
return i - sourceOffset;
}
}
}
return -1;
}
经过测试发现该方法看不懂,因为不管fromIndex传什么都不会影响返回结果,当然只要不大于某个值。
似乎fromIndex这个字段要实现的功能没有实现,jdk10也有很大改动
该发放,没有引用到自己的私有属性,也没有引用什么受保护的jar包,可以粘出来直接测试。
40:截取字符串
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}