0 概述
- String表示字符串,为final类型,定义之后就不能改变
- 字符串缓冲区StringBuilder支持可变的字符串
1 源码分析
1.1 定义
public final class String implements java.io.Serializable, Comparable<String>, CharSequence
- Serializable:用于序列化。
- Comparable<String>:默认的比较器。
- CharSequence:提供对字符序列的统一、只读的操作。
1.2 重要属性
1.2.1 char value[]
/** The value is used for character storage. */
private final char value[];
用于存储字符串内容的字符数组,同样为final类型,初始化之后就不能再更改。
1.2.2 hash
/** Cache the hash code for the string */
private int hash; // Default to 0
String的hash值为一个32位的整型数值,具体的计算方法见hashCode()方法。
1.3 重要的构造方法
String的构造方法有很多种,常用的包括:
1.3.1 使用字符串构造
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
直接将源String的value和hash两个属性赋值给目标String。由于String不可变,所以不用担心源String的值会影响目标String的值。
1.3.2 使用字符数组构造
/**
* Allocates a new {@code String} 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.
*
* @param value
* The initial value of the string
*/
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
用字符数组初始化String,不能直接设置目标String的value为当前参数,因为参数字符数组的变化会影响目标String。需要重新分配一个新的字符数组。
1.3.3 使用StringBuffer和StringBuider构造
public String(StringBuffer buffer) {
synchronized(buffer) {
this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
}
}
public String(StringBuilder builder) {
this.value = Arrays.copyOf(builder.getValue(), builder.length());
}
这两个方法用的很少,一般使用StringBuider的toString()方法得到,效率也比StringBuffer要高。
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
1.3.4 使用字节数组构造
public String(byte bytes[], int offset, int length, Charset charset) {
if (charset == null)
throw new NullPointerException("charset");
checkBounds(bytes, offset, length);
this.value = StringCoding.decode(charset, bytes, offset, length);
}
通过指定Charset编码来进行byte[]与String之间的转化。
1.3.5 特殊的内部构造方法
/*
* Package private constructor which shares value array for speed.
* this constructor is always expected to be called with share==true.
* a separate constructor is needed because we already have a public
* String(char[]) constructor that makes a copy of the given char[].
*/
String(char[] value, boolean share) {
// assert share : "unshared not supported";
this.value = value;
}
其中,share只能为true,因为它只是一个为了区分String(char[])而设计的参数。这种方法直接用引用赋值,不需要复制数组,速度快,同时可以节省内存。但是该方法为包私有,外部不可访问。这是因为影响了String类的不可变性。
这种方式存在“性能问题”。比如jdk6中的subString,直接持有源String的字符数组,如果源String很长,目标String很短,则有性能问题。
比如:
//JDK 6
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
public String substring(int beginIndex, int endIndex) {
//check boundary
return new String(offset + beginIndex, endIndex - beginIndex, value);
}
//JDK 7
public String(char value[], int offset, int count) {
//check boundary
this.value = Arrays.copyOfRange(value, offset, offset + count);
}
public String substring(int beginIndex, int endIndex) {
//check boundary
int subLen = endIndex - beginIndex;
return new String(value, beginIndex, subLen);
}
详情见:https://www.programcreek.com/2013/09/the-substring-method-in-jdk-6-and-jdk-7/
1.4 重要的成员方法
1.4.1 比较方法
boolean equals(Object anObject);//比较内容
boolean equalsIgnoreCase(String anotherString);//忽略大小写的前提下比较内容
int compareTo(String anotherString);//比较大小
int compareToIgnoreCase(String str);
boolean regionMatches(int toffset, String other, int ooffset,int len) //局部匹配
boolean regionMatches(boolean ignoreCase, int toffset,String other, int ooffset, int len) //局部匹配
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;
}
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;
}
1.4.2 hashCode
/**
* Returns a hash code for this string. The hash code for a
* {@code String} object is computed as
* <blockquote><pre>
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
* </pre></blockquote>
* using {@code int} arithmetic, where {@code s[i]} is the
* <i>i</i>th character of the string, {@code n} is the length of
* the string, and {@code ^} indicates exponentiation.
* (The hash value of the empty string is zero.)
*
* @return a hash code value for this object.
*/
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;
}
1.4.3 valueOf
将基本数据类型转为String
public static String valueOf(boolean b) {
return b ? "true" : "false";
}
public static String valueOf(char c) {
char data[] = {c};
return new String(data, true);
}
public static String valueOf(int i) {
return Integer.toString(i);
}
//Integer的toString
public static String toString(int i) {
if (i == Integer.MIN_VALUE)
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
}
1.4.4 intern()方法
native方法,返回对象池中该对象的引用。
/**
* Returns a canonical representation for the string object.
* <p>
* A pool of strings, initially empty, is maintained privately by the
* class {@code String}.
* <p>
* When the intern method is invoked, if the pool already contains a
* string equal to this {@code String} object as determined by
* the {@link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this {@code String} object is added to the
* pool and a reference to this {@code String} object is returned.
* <p>
* It follows that for any two strings {@code s} and {@code t},
* {@code s.intern() == t.intern()} is {@code true}
* if and only if {@code s.equals(t)} is {@code true}.
* <p>
* All literal strings and string-valued constant expressions are
* interned. String literals are defined in section 3.10.5 of the
* <cite>The Java™ Language Specification</cite>.
*
* @return a string that has the same contents as this string, but is
* guaranteed to be from a pool of unique strings.
*/
public native String intern();
1.4.5 对+的重载
String的“+”是java中唯一的一个重载运算符。具体实现如下:
public static void main(String[] args) {
String string="hollis";
String string2 = string + "chuang";
}
反编译为:
public static void main(String args[]){
String string = "hollis";
String string2 = (new StringBuilder(String.valueOf(string))).append("chuang").toString();
}
即String对"+"的支持,实际上是使用StringBuilder的append以及toString。