反编译String类,文件头包中很长的一段介绍里包含了这样的几行文字:
* <p>
* 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. For example:
* <blockquote><pre>
* String str = "abc";
* </pre></blockquote><p>
* is equivalent to:
* <blockquote><pre>
* char data[] = {'a', 'b', 'c'};
* String str = new String(data);
* </pre></blockquote><p>
* Here are some more examples of how strings can be used:
* <blockquote><pre>
* System.out.println("abc");
* String cde = "cde";
* System.out.println("abc" + cde);
* String c = "abc".substring(2,3);
* String d = cde.substring(1, 2);
* </pre></blockquote>
大概意思是:String是常量,一旦定义了就不能改变了。String的buffer类们让String支持可变化,但是String对象本身是不可变但是可共享的。那么为什么会这样呢?比较String类和其他基本数据类型,会发现它们都是被final修饰的类。。。话说回来,既然String对象一旦创建就不可变,那对String对象的操作作何解释?除非每个操作都会创建一个新的String对象?事实上,就是这样的。 String类的声明如下:
public final class Strings
implements java.io.Serializable, Comparable<Strings>, CharSequence {
}
可以看到,String类实现了Serializable接口来保证对象的可序列化,实现了Comparable接口来支持比较,实现了CharSequence类保证String对象的每个元素都是字符(CharSequence本身是一个char值的可读序列)。Serializable接口不需要多说,我们需要重点关注Comparable接口和CharSequence接口。Comparable接口就一个compareTo()方法,在String中的实现如下:
public int compareTo(Strings 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;
}
CharSequence接口的 几个方法:
public interface CharSequence {
/**
* 返回长度
*/
int length();
/**
* 返回指定位置的字符
*/
char charAt(int index);
/**
* 截取指定起点和终点间的字符序列
*/
CharSequence subSequence(int start, int end);
/**
* 转换为字符串
*/
public String toString();
}
String的构造方法很多,如下:
观察每个构造方法,会发现最后都指向了String内部的一个属性:
private final char value[];
结合之前了解到的,String类实现了CharSequence接口,所以String类也等同于一个字符序列,很容易就得到了这样一个结论:String类通过在内部维护一个char数组来实现字符序列。换言之,String类本身就是对char组数的封装?我们来随便找几个常见的
String方法来验证一下这个结论:
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
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 byte[] getBytes() {
return StringCoding.encode(value, 0, value.length);
}
public int length() {
return value.length;
}
看到没有,几乎每个方法里,都有char value[]这个属性的影子,我们的结论是对的。String类,其实真的是对char[]数组的一个封装。