1.String
1.1类的定义
public final class String implements java.io.Serializable, Comparable<String>, CharSequence
String类在定义时候使用final关键字进行修饰,限制了这个类无法被继承,里面的方法也无法被重写。
同时它还实现了Serializable接口、Comparable接口,以及CharSequence接口三个接口:
- Serializable:序列化接口,如果允许对象被序列化需要实现该类。
- Comparable:比较对象大小的接口,用来定义对象之间如何进行大小的比较。
- CharSequence:字符序列接口,相比String类,它是一个更为广泛的可读可写字符序列,而String类是只可读的。
1.2类的成员变
/** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0
String类中常用的两个成员变量value、hash。
- value:字符类型的数组,用来存放我们所保存的字符串,每一个字符串都会被拆开作为字符来进行存储。
- hash:对应字符串的hash值。
1.3常用方法
length():返回value数组的长度。
public int length() { return value.length; }
indexOf(str):获取在字符串中某个字符串的起始位置。这里其实也是用的遍历,从指定的开始位置起,一直遍历直到找到目标字符串,或者直到源字符串的最后一位(其实是最后一位减去目标字符串的长度)。
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); } 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++) { /* Look for first character. */ if (source[i] != first) { while (++i <= max && source[i] != first); } /* Found first character, now look at the rest of v2 */ 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) { /* Found whole string. */ return i - sourceOffset; } } } return -1; }
compareTo(str):比较两个字符串的大小,采用的是逐个字符来进行比较(比较ASCII码)。
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总结
String类是一个可序列化,可按照字符大小进行排序,不可继承、只读的字符序列类。
2.StringBuilder
2.1类定义
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence
StringBuilder和String的定义类似,同样被final关键字修饰,限定了无法被继承,同时继承Serializable和CharSequence两个接口。
同时最它多继承了一个抽象类AblstractStringBuilder。
2.2成员变量
在StringBuilder中没有再定义其他的成员变量,所使用的底层存放数据的变量来自于父类AbstractStringBuilder。
在AbstractStringBuilder中,定义了三个成员变量
char[] value; int count; private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
- value:字符数组,用来存放传入的字符串。
- count:int类型,记录value中存放元素的长度。
- MAX_ARRAY_SIZE:静态常量,代指允许value数组的最大长度。
2.3常用方法
append(str):相比String只读的属性,StringBuilder允许我们对其进行写操作。但是由于底层存放数据的是一个数组,因此每次都需要进行一个扩容的判断。如果count+入参字符串的长度大于当前数组value的长度,就需要进行扩容,每次扩容后的数组长度=原长度*2+2。
public AbstractStringBuilder append(String str) { if (str == null) return appendNull(); int len = str.length(); ensureCapacityInternal(count + len); str.getChars(0, len, value, count); count += len; return this; } private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) { value = Arrays.copyOf(value, newCapacity(minimumCapacity)); } } private int newCapacity(int minCapacity) { // overflow-conscious code int newCapacity = (value.length << 1) + 2; if (newCapacity - minCapacity < 0) { newCapacity = minCapacity; } return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) ? hugeCapacity(minCapacity) : newCapacity; }
2.4总结
StringBuilder补充了String只能读不能写的属性,采用对数组扩容的操作,允许程序员对String类型来进行写操作。
3.StringBuffer
3.1类定义
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence
StringBuffer的定义与StringBuilder类似,同样继承了AbstractStringBuilder抽象类,实现了Serializable和CharSequence接口。
3.2成员变量
StringBuffer的成员变量和StringBuilder一样,同样适用在AbstractStringBuilder中定义好的字符类型数组value和int类型count。
3.3常用方法
append(str):与StringBuilder类似的,两个类都是通过调用AbstractStringBuilder中的append(str)方法来添加字符串。
区别在于StringBuffer的方法定义上多了一个关键字:Synchronized。通过这个关键字,来保证我们对字符串的写操作的线程安全。
@Override public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; }
toString():和StringBuilder的toString()方法不一样,这里在StringBuffer中就已经完成了对字符数组的复制,如果连续调用toString()方法,实际返回的都是同一个String对象。而在StringBuilder中,由于数组的复制是发生在String类里面,因此每次调用后返回的都是不同的String对象。
@Override public synchronized String toString() { if (toStringCache == null) { toStringCache = Arrays.copyOfRange(value, 0, count); } return new String(toStringCache, true); }
3.4总结
StringBuffer在Stringbuilder实现了字符串写操作的基础上,又添加了对它的线程安全方面的维护,通过查看源码,可见都是通过在方法上添加synchronized关键字来显示的。这样虽然可以保证线程安全,但是也在一定程度上,舍弃了部分性能。不过在jdk1.5之后对锁的优化,新增了偏向锁、轻量级锁后,如果我们对字符串的写操作不涉及多线程的时候,StringBuffer和StringBuilder的资源损耗是几乎类似的。但如果一旦涉及多线程,StringBuffer则能更好的保障我们的线程安全。
4.总结
String类是java中定义用来保存一个字符序列的对象,但是对它的操作只有读,而没有写。所有的写操作实际都是返回了一个新的字符串对象。
StringBuilder类在String类的基础上,增加了对字符序列的写操作,采用底层数组扩容的方式,来允许添加新的字符串,或删除里面原有的字符串。
StringBuffer类由在StringBuilder类的基础上,既满足了对字符序列的写操作,又保证了操作的线程安全。因此在实际情况下,优先推荐使用StringBuffer类。
成员变量
String类型