String类的一个最大特性是不可修改性,而导致其不可修改的原因是在String内部定义了一个常量数组,因此每次对字符串的操作实际上都会另外分配分配一个新的常量数组空间(这片空间位于jvm的静态方法区)
- 初始化
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
//数组定义为常量,不可修改
private final char value[];
public String() {
this.value = new char[0];
}
- 实例化字符串
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
- 查找字符串某个位置的字节
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
- 将字节数组转换成字符串
void getChars(char dst[], int dstBegin) {
System.arraycopy(value, 0, dst, dstBegin, value.length);
}
注意:System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)是在底层操作中经常用到的一个数组复制方法
- 获取字符串的长度
public int length() {
return value.length;
}
- 判断string是否为空
public boolean isEmpty() {
return value.length == 0;
}
- 判断两个字符串是否相等(在string中重写了equals的方法,object的equals方法相当于“==”)
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
//先判断是不是sring类型
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;
}
//重写equals是需要重写hashCode方法
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;
}
注意:在重写equals()时也必须要重写hashCode()方法,以保证相同对象的hash值也是一样的,否则会出现意想不到的问题的。因为如果我们对一个对象重写了euqals,意思是只要对象的成员变量值都相等那么euqals就等于true,但不重写hashcode,那么我们再new一个新的对象, 当原对象.equals(新对象)等于true时,两者的hashcode却是不一样的,由此将产生了理解的不一致,导致混淆
- 获得某个字符的所在位置
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) {
// 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) {
return i;
}
}
return -1;
} else {
return indexOfSupplementary(ch, fromIndex);
}
}
- 获得子字符串(注意这里是不会在原来的字符串修改的,修改之后也是放到一个新的字符数组中)
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);
}
//注意这里是以长度取子字符串,因此endIndex最后一位不会被娶上
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
- 连接两个字符串
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字符串的内容按照长度获取放进buf数组中
str.getChars(buf, len);
return new String(buf, true);
}
- 将字符串储存到字节数组中
public char[] toCharArray() {
char result[] = new char[value.length];
System.arraycopy(value, 0, result, 0, value.length);
return result;
}
最后补充一点:
StringBuffer、StringBuilder和String一样,也用来代表字符串。String类是不可变类,任何对String的改变都 会引发新的String对象的生成;StringBuilder则是可变类,任何对它所指代的字符串的改变都不会产生新的对象,而StringBuilder则是线程安全版的StringBuilder。