Java源码分析

一、String类

1、string不可变的理由:

  • public final class StringStringfinal类,不可继承
  • 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的区别

    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等方法。

参考文章:一起学JDK源码 – String类

发布了33 篇原创文章 · 获赞 2 · 访问量 966

猜你喜欢

转载自blog.csdn.net/Rhin0cer0s/article/details/100908136