String概述
String类型是java的一个最基本的对象,他底层是用char[]实现,是一个不可继承类,即final类。
String是我们平时使用最多的,所以我们要深入理解String类他的实现和底层。
前置:value是字符数组,而且是一个常量不可变,。
hash 默认是0
构造函数
无参构造
String类型的无参构造,他是将空字符串给了char[]
public String() {
this.value = "".value;
}
值得注意的是String new与不new的区别是什么??
我们熟知JVM有堆,栈,方法区,方法区里存放这常量池。
当我们使用String类型直接赋值的时候,首先会去常量池查看是否已经有这个常量,如果有就不需要创建了直接引用就行了,没有就创建在引用。但是如果使用了new的方式来创建这个String,那么中间就会多一步过程,当我们在new的时候,它首先会查看常量池是否有这个常量,如果有的话,那么直接获取这个地址,但是因为他new了,所以会在堆中创建一个String的实例,然后这个实例引用了常量池的地址,而栈中的变量就引用了堆中实例的地址,也就是说new的话,会占用两块内存空间。所以一般推荐不要使用new的方式来创建。
构造方法参数为String类型
这种方法就是一个赋值的过程
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
一般情况下,除非需要显式副本,那么不需要使用这个构造函数,因为字符串是不可变的(官方)
char[]参数的构造函数
这个构造函数就是为了把字符数组转换为一个String类型的字符串。
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
他调用了Arrays的copyOf方法,这个方法底层调用了System的arraycopy方法,是一个native方法,这是一个本地方法,也就是说他是通过JVM来实现的,效率相比其他转换方法要高。
char[],int,int 参数构造方法
两个int的值分别表示偏移量和数量,最底层也是调用了System的arraycopy方法。就不多讲了
int[],int,int 参数构造方法
int数组怎么转换为字符串类型?基础好的同学会清楚UNICODE ,他会将int类型转换为UNICODE所代表的相应字符,在早起UNICODE用char是能够全部表示的,但是在UNICODE4.0之后规定的支持字符远超与char所能支持,所以使用了int类型来进行代替。
public String(int[] codePoints, int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= codePoints.length) {
this.value = "".value;
return;
}
}
// 偏移量判断
if (offset > codePoints.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
final int end = offset + count;
// 1.计算char []的精确大小
int n = count;
for (int i = offset; i < end; i++) {
int c = codePoints[i];
// 判断是否能够被char表示
if (Character.isBmpCodePoint(c))
continue;
// 校验是否是UNICODE代码点 如果能长度+1 否则抛出异常
else if (Character.isValidCodePoint(c))
n++;
else throw new IllegalArgumentException(Integer.toString(c));
}
// 2.填充和分配char []
final char[] v = new char[n];
for (int i = offset, j = 0; i < end; i++, j++) {
int c = codePoints[i];
if (Character.isBmpCodePoint(c))
v[j] = (char)c;
else
// 转换成char能表示的字符
Character.toSurrogates(c, v, j++);
}
this.value = v;
}
byte[],int,int,String 构造函数
参数意义:字节数组,偏移量,数量,字符集名称(对应java.nio.charset.Charset);
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);
}
字符集默认使用的是什么?ISO-8859-1.
注意:字符集需要是java.nio.charset.Charset包含的,如果不存在就会抛出UnsupportedEncodingException。
static char[] decode(String charsetName, byte[] ba, int off, int len)
throws UnsupportedEncodingException
{
StringDecoder sd = deref(decoder);
String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
具体解码过程自行查看。
相似的构造函数
1.public String(byte bytes[], int offset, int length, Charset charset)
2.public String(byte bytes[], String charsetName)
3.public String(byte bytes[], Charset charset)
4.public String(byte bytes[], int offset, int length)
5.public String(byte bytes[])
StringBuffer 参数构造函数和StringBuilder 参数构造函数
这两种主要的区别就是加锁,线程安全的问题,也不多复述了.
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());
}