题记:
String作为我们工作中最常用的类之一,一直没有完整的看过其底层的源码
类:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence { }
1.String类的修饰符有一个final所以它是不能被继承的
2.实现接口
java.io.Serializable这是一个序列化接口里面没有任何方法和域,仅用于标识序列化
Comparable<String> 标识这个接口,用于对两个实例化对象比较大小
CharSequence 这个接口是一个只读的字符序列。包括length(), charAt(int index), subSequence(int start, int end)这几个API接口,值得一提的是,StringBuffer和StringBuild也是实现了改接口。
一.成员变量
1.char value[]
private final char value[];
是用于存储String的内容的 每个字符串实际上都是一个char[]数组 例如String str = "ABC",实际存储为char[] str = {'A','B','C'}
2.int hash
private int hash;
这里的hash是String实例化的hashcode的一个缓存,使用私有变量缓存了hash值 使用了利用空间来换取时间
3.long serialVersionUID
private static final long serialVersionUID = -6849794470754667710L;
用于版本判定
4.OjectStreamField[] serialPersistentFields
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
需要序列化的部分
二.构造器
JDK1.8中String类一共由16个构造器其中 有两个带有@Deprecated(不推荐使用) 一个私有构造器
1.无参构造器
public String() { this.value = "".value; }
无参构造器直接将""的value赋值给当前类的value. value的length则为0,当前是一个""(空字符串)而不是null hashCode为0
2.传入参数为String对象
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
构造器直接对其进行取值
3.传入参数为char[]
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
构造器==>>Arrays.copyOf()方法==>>System.arraycopy();进行了拷贝
public static char[] copyOf(char[] original, int newLength) {
char[] copy = new char[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
4.传入char[]数组,偏移量(下标)和长度
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
通过offset(偏移量)和count(长度)来查找子串并赋值给this.value然后调用Arrays.copyOfRange方法进行深拷贝
char[] chars = {'A','B','C'};
String str = new String(chars,1,2); //BC
注意: offset不能填入负数也不能填入超出数组长度的数值 count也不能填入负数也不能填入超出剩余长度的值
否则会抛出 java.lang.StringIndexOutOfBoundsException: String index out of range 异常
5.传入char[]数组,偏移量(下标)和长度
public String(char value[], int offset, int count){}
6. 传入int[]数组最后获得的是相对应的Unicode的字符
public String(int[] codePoints, int offset, int count){}
int[] arr = {97,99,98};
String str = new String(arr,0,arr.length); //abc
7.弃用的方法
@Deprecated
public String(byte ascii[], int hibyte, int offset, int count){}
8.弃用的方法
@Deprecated
public String(byte ascii[], int hibyte) {}
9. 传入byte[]数组,偏移量(下标)和长度, charsetName编码格式 生成新的字符串
public String(byte bytes[], int offset, int length, String charsetName)
throws UnsupportedEncodingException{}
10.传入byte[]数组,偏移量(下标)和长度,charset字符集
public String(byte bytes[], int offset, int length, Charset charset)
Charset charset = Charset.forName("UTF-8"); //指定字符集
String str = new String(bytes,0,3,charset);
11.传入byte[]数组,charsetName编码格式 生成新的字符串
public String(byte bytes[], String charsetName)
throws UnsupportedEncodingException {}
12.通过使用平台默认的字符集构造一个新的String 传入 byte[]数组,偏移量(下标)和长度
public String(byte bytes[], int offset, int length) {}
13.传入byte[]数组 调用的是12的构造方法
public String(byte bytes[]) { this(bytes, 0, bytes.length); }
14.15. 传入可变字符串对象
public String(StringBuffer buffer){ //StringBuffer
synchronized(buffer) {
this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
}
}
public String(StringBuilder builder){ //StringBuilder
this.value = Arrays.copyOf(builder.getValue(), builder.length());
}
因为StringBuffer 是线程安全的 所以会添加锁,而StringBuilder是线程不安全的所以不会进行添加锁
最终的实现都是通过Arrays.copyOf() 他们的toString方法都调用了String的方法
@Override
public synchronized String toString() { //StringBuffer的toString方法
if (toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
}
return new String(toStringCache, true);
}
@Override
public String toString() { //StringBuilder的toString方法
// Create a copy, don't share the array
return new String(value, 0, count);
}
16.这是一个保护类型的构造方法.我们不能调用这个方法
String(char[] value, boolean share) {
// assert share : "unshared not supported";
this.value = value;
}
该方法相比传入为char[]的构造方法多了一个share(共享)的boolean参数,这个参数并没有实际作用,
只是为了和其他构造器进行区分.当String类内部调用该构造器时
(1) 直接进行赋值而不是使用Arrays.copyOf()方法效率会提高
(2) 共享字符串数组方式可以节省内存