一、String类
1、string不可变的理由:
public final class String
:String
是final
类,不可继承private final char value[]
:成员变量用final
修饰,变成常量。常量的好处是线程安全。(如果通过反射还是可以修改value的)- 用
private
修饰 表示成员变量独有,其他程序不能操作value
字符数组
2、public final class String implements java.io.Serializable, Comparable<String>, CharSequence
Serializable 可以序列化和反序列化
Comparable 支持字符串的比较
CharSequence 说明它是一个字符序列。
3、成员变量
private final char value[]; //存储字符串
private int hash; //字符串的hash code 默认是0
private static final long serialVersionUID = -6849794470754667710L; //序列化id
4、构造方法
public String() {this.value = "".value;}
无参构造,值为空串,基本不用
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
参数String对象参数来构造String对象,该构造函数经常被用来做面试题。
问new String(“abc”);共创建了几个对象。
答案是两个,字面量"abc"创建一个对象放在常量池中,new String()又创建一个对象放在堆中。
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
通过整个char数组参数来构造String对象,实际将参数char数组值复制给String对象的char数组。
public String(byte bytes[], int offset, int length, String charsetName)
throws UnsupportedEncodingException {
if (charsetName == null)
throw new NullPointerException("charsetName");
checkBounds(bytes, offset, length);
this.value = StringCoding.decode(charsetName, bytes, offset, length);
}
通过byte数组构造String对象,将入参byte数组中指定内容,用指定charsetName的字符集转换后构造String对象。
其中StringCoding.decode(charsetName, bytes, offset, length)
是根据指定编码对byte数组进行解码,解码返回char数组。
checkBounds(bytes, offset, length)
是对参数进行检查
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指定的,上述是用String指定的。
Charset与charsetName是表示字符集的两种不同形式
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());
}
通过上面两个构造String对象,它们内部都维护了一个char数组,这里将它们数组中的内容复制给String对象中的数组。
唯一不同的是一个是线程安全,另一个不安全。StringBuffer与StringBuilder的区别扫描二维码关注公众号,回复: 9401589 查看本文章
String(char[] value, boolean share) {
// assert share : "unshared not supported";
this.value = value;
}
这个构造函数很有趣。
首先它同String(char[] value)
相比多了个参数share,虽然在方法本身没有用到share。
这个方法定义成这样是为了同String(char[] value)
进行区分。否则没办法构成方法重载。
再来看下这个方法的作用。它是直接将参数的地址传给了String对象,这样要比直接使用String(char[] value)
的效率要高,因为String(char[] value)
是逐一拷贝。
有人会问这样String对象和参数传过来的char[] value共享同一个数组,不就破坏了字符串的不可变性。设计都也考虑到了,所以它设置了保护用 protected 修饰而没有公开出去。所以从安全性角度考虑,他也是安全的。
在java中也有很多地方用到了这种性能好的、节约内存的、安全的构造函数。如replace、concat、valueOf等方法。