Java源码阅读之String(1)

Java源码阅读之String(1)

      String类表示字符串。 Java程序中的所有字符串文字(例如“abc”)都是作为这个类的实例来实现的。 String的实例创建之后值就不能被修改。StringBuffer和StringBuilder支持可变的字符串。因为字符串对象是不可变的,所以它们可以共享。String类底层是用char数组存储值的,它实现了java.io.Serializable, Comparable, CharSequence三个接口,三个接口的作用分别是:

  • 1、Serializable 是一个标志接口,意思是实现了这个接口的类的对象可以被序列化。
  • 2、Comparable 是实现比较大小的接口。
  • 3、CharSequence接口,标志这实现了这个接口的对象是一个字符 char 序列。

      这一篇博客就主要分析一下String类的构造方法。

private final char value[];//value数组用于存储字符串的值

private int hash; // 缓存字符串的哈希码 默认值为0

//无参构造方法,默认将空字符串的值赋值给新建实例
public String() {
    this.value = "".value;
}

/*根据一个已有的字符串创建新的实例,这里可以看到
*只是将original的值的引用赋值给新的实例的value
*并没有将original的值复制一份
*/
public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}

/*根据一个已有的字符数组创建新的实例,这里可以看到
*将value数组的值复制了一份赋值给新的实例的value
*/
public String(char value[]) {
    this.value = Arrays.copyOf(value, value.length);
}

/*根据一个已有的字符数组中的指定偏移量和长度创建新的实例,这里可以看到
*将value数组的值根据偏移量和长度复制了一份赋值给新的实例的value
*offset是偏移量也就是从value数组的什么位置开始复制
*count是需要复制的长度
*/
public String(char value[], int offset, int count) {
    //偏移量小于0 抛出异常
    if (offset < 0) {
        throw new StringIndexOutOfBoundsException(offset);
    }
    if (count <= 0) {
        //长度小于0 抛出异常
        if (count < 0) {
            throw new
                StringIndexOutOfBoundsException(count);
        }
        //长度等于0 且偏移量小于等于传入的value数组长度
        //则将空字符串的值赋给新建的实例
        if (offset <= value.length) {
            this.value = "".value;
            return;
        }
    }
    //这里我觉得这样更好理解 offset + count > value.length
    //如果截取的长度超过value数组的长度则抛出异常
    if (offset > value.length - count) {
        throw new StringIndexOutOfBoundsException(offset + 
            count);
    }
    //根据传入的偏移量和长度复制value数组中的值,作为一个新的数组
    //赋值给新建实例的value
    this.value = Arrays.copyOfRange(value, offset, 
        offset+count);
}

/*根据一个已有的int数组中的指定偏移量和长度创建新的实例,这里可以看到
*将codePoints数组的值根据偏移量和长度复制了一份赋值给新的实例的value
*offset是偏移量也就是从value数组的什么位置开始复制
*count是需要复制的长度
*这里的值不是简单的直接转换为char而是将int的值作为unicode编码值赋值
*给value数组
*/
public String(int[] codePoints, int offset, int count) {
    //偏移量小于0 抛出异常
    if (offset < 0) {
        throw new StringIndexOutOfBoundsException(offset);
    }
    if (count <= 0) {
        //长度小于0 抛出异常
        if (count < 0) {
            throw new 
                StringIndexOutOfBoundsException(count);
        }
        //长度等于0 且偏移量小于等于传入的value数组长度
        //则将空字符串的值赋给新建的实例
        if (offset <= codePoints.length) {
            this.value = "".value;
            return;
        }
    }
    //这里我觉得这样更好理解 offset + count > value.length
    //如果截取的长度超过value数组的长度则抛出异常
    if (offset > codePoints.length - count) {
        throw new StringIndexOutOfBoundsException(offset + 
            count);
    }
    //end记录需要复制到的最大位置+1
    final int end = offset + count;
    //n用于计算新的实例的value的长度
    int n = count;
    for (int i = offset; i < end; i++) {
        int c = codePoints[i];
        //判断当前数字是否属于BMP代码点
        //有效的BMP代码点范围是 \u0000至 \uFFFF也就是说当前
        //Unicode编码长度为两个字节一个char可以放下
        if (Character.isBmpCodePoint(c))
            continue;
        //判断当前数字是否属于Unicode编码
        //Unicode编码的有效范围是0x000000至0X10FFFF
        //如果是Unicode编码却不是BMP编码 那么就需要两个char才能记
        //录一个高位Unicode编码
        else if (Character.isValidCodePoint(c))
            n++;
        else throw new 
            IllegalArgumentException(Integer.toString(c));
    }
    final char[] v = new char[n];
    for (int i = offset, j = 0; i < end; i++, j++) {
        int c = codePoints[i];  
        //记录一个BMP的编码    
        if (Character.isBmpCodePoint(c))
            v[j] = (char)c;
        else
            //将当前数字分为高十六位和低十六位分开记录到
            //v数组的两个char中
            Character.toSurrogates(c, v, j++);
    }
    this.value = v;
}

/*检查偏移量参数offset和长度参数length是否合法
*/
private static void checkBounds(byte[] bytes, int offset, 
    int length) {
    if (length < 0)
        throw new StringIndexOutOfBoundsException(length);
    if (offset < 0)
        throw new StringIndexOutOfBoundsException(offset);
    if (offset > bytes.length - length)
        throw new StringIndexOutOfBoundsException(offset + 
            length);
}

/*将给定的byte数组以给定的编码方式转换为char数组复制给新建实例value
*给定的编码方式为编码名如“UTF-8”
*转换范围为offset到offset+length
*/
public String(byte bytes[], int offset, int length, String 
    charsetName) throws UnsupportedEncodingException {
    if (charsetName == null)
        throw new NullPointerException("charsetName");
    //检查参数是否合法
    checkBounds(bytes, offset, length);
    //将给定的byte数组以给定的编码方式转换为char数组
    this.value = StringCoding.decode(charsetName, bytes, 
        offset, length);
}

/*将给定的byte数组以给定的编码方式转换为char数组复制给新建实例value
*给定的编码方式为CharSet类型,如CharSet.forName(“UTF-8”)
*转换范围为offset到offset+length
*/
public String(byte bytes[], int offset, int length, Charset 
    charset) {
    if (charset == null)
        throw new NullPointerException("charset");
    //检查参数是否合法
    checkBounds(bytes, offset, length);
    //将给定的byte数组以给定的编码方式转换为char数组
    this.value =  StringCoding.decode(charset, bytes, 
        offset, length);
}

/*将给定的byte数组以给定的编码方式转换为char数组复制给新建实例value
*给定的编码方式为编码名如“UTF-8”
*默认转换的bytes范围为全部
*/
public String(byte bytes[], String charsetName)
       throws UnsupportedEncodingException {
    //调用重载构造方法
    this(bytes, 0, bytes.length, charsetName);
}

/*将给定的byte数组以给定的编码方式转换为char数组复制给新建实例value
*给定的编码方式为CharSet类型,如CharSet.forName(“UTF-8”)
*默认转换的bytes范围为全部
*/
public String(byte bytes[], Charset charset) {
    //调用重载构造方法
    this(bytes, 0, bytes.length, charset);
}

/*将给定的byte数组以默认的编码方式转换为char数组复制给新建实例value
*默认的编码方式为“ISO-8859-1”
*转换范围为offset到offset+length
*/
public String(byte bytes[], int offset, int length) {
    checkBounds(bytes, offset, length);
    this.value = StringCoding.decode(bytes, offset, 
        length);
}

/*将给定的byte数组以默认的编码方式转换为char数组复制给新建实例value
*默认的编码方式为“ISO-8859-1”
*转换范围为bytes全部
*/
public String(byte bytes[]) {
    //调用重载构造方法
    this(bytes, 0, bytes.length);
}

/*以给定的StringBuffer对象构建新的实例
*将StringBuffer的value值复制一份赋值给当前新建对象的value
*/
public String(StringBuffer buffer) {
    //因为StringBuffer是线程安全的所以这里需要将
    //StringBuffer对象锁住
    synchronized(buffer) {
        this.value = Arrays.copyOf(buffer.getValue(), 
            buffer.length());
    }
}

/*以给定的StringBuilder 对象构建新的实例
*将StringBuilder 的value值复制一份赋值给当前新建对象的value
*/
public String(StringBuilder builder) {
    this.value = Arrays.copyOf(builder.getValue(), 
        builder.length());
}

/*这是一个包的私有构造函数 不需要我们调用,因为String已经提供了
*一个以char[]为参数的构造函数。
*/
String(char[] value, boolean share) {
    // assert share : "unshared not supported";
    this.value = value;
}

      String类的构造方法就是这些,几个已经被弃用的我并没有列出来,如果有兴趣还请参阅Java源码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值