试读java源码之String(1)——String的构造方法

String是我们java开发中最常用的类,在此我试着通读String源码,并写下自己的感想


String中实现了

implements java.io.Serializable, Comparable<String>, CharSequence

java.io.Serializable,表示序列化,是一个空接口,也就是说这个接口没有声明任何的方法,所以实现这个接口的类也就不需要实现任何的方法。   

Comparable<String>

此接口强行对实现它的每个类的对象进行整体排序。此排序被称为该类的自然排序 ,类的 compareTo 方法被称为它的自然比较方法 。实现此接口的对象列表(和数组)可以通过 Collections.sort (和 Arrays.sort )进行自动排序。实现此接口的对象可以用作有序映射表中的键或有序集合中的元素,无需指定比较器。 强烈推荐(虽然不是必需的)使自然排序与 equals 一致。所谓与equals一致是指对于类 的每一个 e1 和 e2 来说,当且仅当 (e1.compareTo((Object)e2) == 0) e1.equals((Object)e2) 具有相同的布尔值时,类 的自然排序才叫做与 equals 一致 


String 继承于CharSequence,也就是说String也是CharSequence类型。
CharSequence是一个接口,它只包括length(), charAt(int index), subSequence(int start, int end)这几个API接口。除了String实现了CharSequence之外,StringBuffer和StringBuilder也实现了CharSequence接口。
需要说明的是,CharSequence就是字符序列,String, StringBuilder和StringBuffer本质上都是通过字符数组实现的!




String声明了char数组,int型,UID,ObjectStreamField[]四个私有变量

private final char value[];


private int hash; 

private static final long serialVersionUID = -6849794470754667710L;

private static final ObjectStreamField[] serialPersistentFields =
        new ObjectStreamField[0];

其中

serialPersistentFields 

尚不理解,暂且跳过.


下面是String自身的构造方法


1.

public String() {
    this.value = new char[0];
}

简单没有任何传参的构造方法,声明一个长度为0的char数组

2.

public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}

传入一个String类型的数据,把此String装配为char[]数组,长度传为int.

其实很奇怪的是,String中可以自己调取自己吗..

3.

public String(char value[]) {
    this.value = Arrays.copyOf(value, value.length);
}

传入一个char数组,通过copyOf方法复制此数据

其实有点搞不懂哎,为啥不直接传值,而是通过Arrays来传入


4.

public String(char value[], int offset, int count) {
    if (offset < 0) {
        throw new StringIndexOutOfBoundsException(offset);
    }
    if (count < 0) {
        throw new StringIndexOutOfBoundsException(count);
    }
    // Note: offset or count might be near -1>>>1.
    if (offset > value.length - count) {
        throw new StringIndexOutOfBoundsException(offset + count);
    }
    this.value = Arrays.copyOfRange(value, offset, offset+count);
}

传入char数组,两个int参数,如果int小于0或者offset大于数组本身长度减去count则返回异常

否则使用copyOfRange函数,复制一个传入数组offset----(offset+count)范围的数组

5.

public String(int[] codePoints, int offset, int count) {
    if (offset < 0) {
        throw new StringIndexOutOfBoundsException(offset);
    }
    if (count < 0) {
        throw new StringIndexOutOfBoundsException(count);
    }
    // Note: offset or count might be near -1>>>1.
    if (offset > codePoints.length - count) {
        throw new StringIndexOutOfBoundsException(offset + count);
    }

    final int end = offset + count;

    // Pass 1: Compute precise size of char[]
    int n = count;
    for (int i = offset; i < end; i++) {
        int c = codePoints[i];
        if (Character.isBmpCodePoint(c))
            continue;
        else if (Character.isValidCodePoint(c))
            n++;
        else throw new IllegalArgumentException(Integer.toString(c));
    }

    // Pass 2: Allocate and fill in 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
            Character.toSurrogates(c, v, j++);
    }

    this.value = v;
}


传入unicode字符集

前面首先判断是否有负值或者非0值,如果没有则声明

final int end = offset+count;

int n =count;

for (int i = offset; i < end; i++) {
    int c = codePoints[i];
    if (Character.isBmpCodePoint(c))
        continue;
    else if (Character.isValidCodePoint(c))
        n++;
    else throw new IllegalArgumentException(Integer.toString(c));
}

以offset为起点遍历count长度的传入int数组

循环判断编码类型

如果为Bmp则跳过循环,如果是valid则使n+1


final char[] v = new char[n];

完成循环后,声明一个以当前n值为长度的,其中如含有bmp类型的则为正常长度,为valid但不为bmp的为两个长度

char数组

for (int i = offset, j = 0; i < end; i++, j++) {
    int c = codePoints[i];
    if (Character.isBmpCodePoint(c))
        v[j] = (char)c;
    else
        Character.toSurrogates(c, v, j++);
}

此时继续进行循环

以offset为基准,遍历数组

经过我自己的测试后发现:BmpCodePoint代码点是65535是2的16次方,刚好是两个字节(即一个字)的大小。在超出两个字节后只能算是有效的代码点,并非是BmpCodePoint代码点。从代码中也可看出,BmpCodePoint代码点的整数是可以直接强转成char类型的。在java中char类型刚好占2个字节,在2个字节以内的整数都可以直接强转换成char类型


---------------------------------------

其实就是根据输入的unicode编码转换字符串,如果超出unicdoe的编码范围,则去取最大值0xffff.



6.


public String(byte ascii[], int hibyte, int offset, int count) {
    checkBounds(ascii, offset, count);
    char value[] = new char[count];

    if (hibyte == 0) {
        for (int i = count; i-- > 0;) {
            value[i] = (char)(ascii[i + offset] & 0xff);
        }
    } else {
        hibyte <<= 8;
        for (int i = count; i-- > 0;) {
            value[i] = (char)(hibyte | (ascii[i + offset] & 0xff));
        }
    }
    this.value = value;
}
 checkBounds(ascii, offset, count);

校检长度是否符合规则


如果输入的长度符合规则

则声明一个count长度的char数组

  value[i] = (char)(ascii[i + offset] & 0xff);
&

按位与

比如以下例子

System.out.println(0x55 & 0xff);
System.out.println(0xff);
System.out.println(0x55);
85
255

85


0x55=01010101

0xff=11111111

=01010101

实际上来看,如果按位与0xff,并不会对返回的结果产生实质上的反应,这个反而是为了防止溢出ASCII码吧

hibyte <<= 8;

位移动符

int a =512;
        a >>= 3;
    System.out.println(64);

相当于512^1/2^3

7.

public String(byte ascii[], int hibyte) {
    this(ascii, hibyte, 0, ascii.length);
}
this(ascii, hibyte, 0, ascii.length);
是调取上一个方法


8.

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);
}



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;
    if ((sd == null) || !(csn.equals(sd.requestedCharsetName())
                          || csn.equals(sd.charsetName()))) {
        sd = null;
        try {
            Charset cs = lookupCharset(csn);
            if (cs != null)
                sd = new StringDecoder(cs, csn);
        } catch (IllegalCharsetNameException x) {}
        if (sd == null)
            throw new UnsupportedEncodingException(csn);
        set(decoder, sd);
    }
    return sd.decode(ba, off, len);
}

看不懂



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值