1.String类型是不可变的,除了StringBuffer可以改变String之外。 * Strings are constant; their values cannot be changed after they * are created. String buffers support mutable strings. * Because String objects are immutable they can be shared.
2.public final class String implements java.io.Serializable, Comparable<String>, CharSequence
String类实现了java.io.Serializable接口,Comparable接口以及CharSequence的接口,接下来分别简述一下这些接口:
java.io.Serializable:该接口没有具体方法需要实现,只是标记了该类是可以被序列化的类。具体序列化的知识会再写一篇序列化的总结,目前可以先参考https://www.cnblogs.com/wangg-mail/p/4354709.html中的对序列化的讲解,其中比较重要的有transient关键字以及serialVersionUID属性,以及知识点,如果父类没有标记可序列化,子类标记序列化,那么父类的属性就不能被序列化。
Comparable:实现类的自然排序,实现compareTo方法。
CharSequence:包括了length(), charAt(int index), subSequence(int start, int end)等方法。
3.private final char value[];
String类型的第一个属性,用于存储字符数据。
4.private int hash;
String类型的第二个属性,用于缓存String字符串的hash值,默认为0。
5.private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];
String类型的第三个属性,一个有关于流的对象数组(不理解是做啥的)
6.public String() { this.value = new char[0]; }
构造方法,为空的时候构造一个长度为0的char数组,但是注释中说,因为Stirng的不可变性,这个构造器变得没有用处。
7.public String(String original) { this.value = original.value; this.hash = original.hash; }
构造方法,传入一个String将其属性赋值给new出来的新的String,注释中表示,除非非常有必要的赋值,不然这样的构造也是不需要的。
8.public String(char value[]) { this.value = Arrays.copyOf(value, value.length); }
构造方法,表示将一个char数组赋值给String,注释中说明,char[]如果有后续的改变是不会改变String的。
9.public String(char value[], int offset, int count) { if (offset < 0) { throw new StringIndexOutOfBoundsException(offset); } if (count < 0) { throw new StringIndexOutOfBoundsException(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); }
构造方法,截取字符数组的片段来生成String
10.public String(int[] codePoints, int offset, int count) { if (offset < 0) { throw new StringIndexOutOfBoundsException(offset); } if (count < 0) { throw new StringIndexOutOfBoundsException(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 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; }
构造方法,通过整型数组来构造String,原理是Unicode,其中在构造时会判断char的具体大小,因为,int型所代表的大小可能会超过char的大小(2字节)所以,需要精确计算变成char[]的大小,如果是isBmpCodePoint,说明是两个字节之内,可以直接强转成char,如果超过2字节,那么会用两个char来接这个unicode(涉及Unicode知识,待后续补充)
接下来省略一些构造方法。。。
11.public String(StringBuffer buffer) { synchronized(buffer) { this.value = Arrays.copyOf(buffer.getValue(), buffer.length()); } }
构造方法,用StringBuffer来构造,会发现这里对入参buffer加了synchronized锁,意思是当线程获得buffer对象的monitor的时候,如果访问了String类的该锁块的构造方法,那么buffer对象会被加上锁,其他的线程就不能访问这个buffer。
12.public String(StringBuilder builder) { this.value = Arrays.copyOf(builder.getValue(), builder.length()); }
构造方法,用StringBuilder来构造。
13.public int length() { return value.length; }
返回字符串长度,其实可以发现其实字符串长度返回的就是char[]的长度。
14.public boolean isEmpty() { return value.length == 0; }
检查是否为空,判断的方式是length==0。
15.public char charAt(int index) { if ((index < 0) || (index >= value.length)) { throw new StringIndexOutOfBoundsException(index); } return value[index]; }
返回规定下标的char。
16.public byte[] getBytes(Charset charset) { if (charset == null) throw new NullPointerException(); return StringCoding.encode(charset, value, 0, value.length); }
常用的方法转化字符串的字符集编码(具体如何实现的待分析),返回byte数组,一般会讲这个byte数组new一个新的String,就可以将String的字符集编码转化。
17.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重写了Object的equals方法,首先直接先判断他们的内存地址是否一样,如果一样直接返回true,然后判断入参是否是String类型不是的话直接返回false,再判断value[]的长度,如果相等的话,才继续判断他们其中的值。
18.public boolean contentEquals(StringBuffer sb) { return contentEquals((CharSequence)sb); }
19.private boolean nonSyncContentEquals(AbstractStringBuilder sb) { char v1[] = value; char v2[] = sb.getValue(); int n = v1.length; if (n != sb.length()) { return false; } for (int i = 0; i < n; i++) { if (v1[i] != v2[i]) { return false; } } return true; }
20.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.equals(this)) return true; // 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; }
判断StringBuffer与String是否相等,值得注意的是StringBuffer是可以强转的charSqeuence的,通过【19】的代码我们可以知道,StringBuffer和StringBuilder都继承了AbstractStringBuilder,在这个【20】contentEquals的方法上,只是StringBuffer被加了锁。
21.public boolean equalsIgnoreCase(String anotherString) { return (this == anotherString) ? true : (anotherString != null) && (anotherString.value.length == value.length) && regionMatches(true, 0, anotherString, 0, value.length); }
忽略大小写判断两个字符串是否相等其中,regionMatches是判断字符串在某个区间是否相等,第一个true表示忽略大小写。
22.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) { // If characters don't match but case may be ignored, // try converting both characters to uppercase. // If the results match, then the comparison scan should // continue. char u1 = Character.toUpperCase(c1); char u2 = Character.toUpperCase(c2); if (u1 == u2) { continue; } // Unfortunately, conversion to uppercase does not work properly // for the Georgian alphabet, which has strange rules about case // conversion. So we need to make one last check before // exiting. if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) { continue; } } return false; } return true; }
除了会检查toUpperCase以外,还会检查toLowerCase