String源码分析

Class About String In  Package Of Java Lang

这篇笔记主要用于分析Java中String系列的源代码。以下是String系列的的类层次结构图。这篇博文主要目的在于分析String系列源码思想、以及String系列类型之间的关系,以及性能等。

 

 

第一序  String类型源码解析

String类型是一个final类型,是不允许继承一改变的。

1.持有成员变量

          一直疑惑String字符串类型为什么那么类似于字符数组char[ ],分析源码后将会发现,本质就是字符数组。String类型持有私有访问权限的字符数组。

源码:privatefinal char value[];

都发现String中的字符串是连续不可变的,也正说明该value[ ]数组是final类型。同事Java程序中将类似于“abc”这样的字符串编译为String类型的实例对象,至于这个实现细节有待于进一步学习!

同时String类型实现了Serializable序列化标记接口,所以拥有序列化ID。

源码:privatestaticfinallongserialVersionUID= -6849794470754667710L;

String类型持有一个整形,作为hash值。

源码:private int hash;

 

2.实例构造器

a.无参构造器

 publicString() {
        this.value= new char[0];

    }

 

b.字符数组作为入参构造器

 publicString(charvalue[]) {
        this.value= Arrays.copyOf(value,value.length);

    }

 

c.”abc”这样的字符串作为入参构造器

 publicString(Stringoriginal) {
        this.value= original.value;
        this.hash= original.hash;

    }

 

d.整形数组作为入参构造器

 publicString(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 (inti =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 (inti =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;

    }

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

这里需要了解Unicode字符的原理,以及代码点的概念!

 

e.字节数组作为入参构造器

 publicString(bytebytes[],int offset,int length, StringcharsetName)
            throws UnsupportedEncodingException {
        if (charsetName== null)
            throw new NullPointerException("charsetName");
        checkBounds(bytes,offset,length);
        this.value= StringCoding.decode(charsetName,bytes,offset,length);

    }

 

f.StringBuffer作为入参构造器

g.StringBuilder作为入参构造器

 

3.成员方法

getChars( int srcBegin,int srcEnd,char dst[],int dstBegin)源码:

 publicvoid getChars(intsrcBegin,int srcEnd,char dst[],int dstBegin) {
        if (srcBegin< 0) {
            throw new StringIndexOutOfBoundsException(srcBegin);
        }
        if (srcEnd> value.length) {
            throw new StringIndexOutOfBoundsException(srcEnd);
        }
        if (srcBegin> srcEnd) {
            throw new StringIndexOutOfBoundsException(srcEnd- srcBegin);
        }
        System.arraycopy(value,srcBegin,dst,dstBegin,srcEnd - srcBegin);

    }

其中调用了System类的本地方法arraycopy( ),判断是否数组越界:开始位置是否大于0,结束位置是否大于字符串长度,开始位置是否小于0。然后子调用本地方法从开始位置到结束位置将字符串复制到目的字符串中。

 

String的equals( )方法被重写,首先判断两个String对象是否相等,如果不等再判断两个String对象的字符是否相等。

 

indexOf(int ch,  int fromIndex)源码:

publicint indexOf(intch,int fromIndex) {
        final int max =value.length;
        if (fromIndex< 0) {
            fromIndex = 0;
        } else if (fromIndex>= max) {
            // Note: fromIndex might be near -1>>>1.
            return -1;

        }

       if (ch< Character.MIN_SUPPLEMENTARY_CODE_POINT) {
            // handle most cases here (ch is a BMP code point or a
            // negative value (invalid code point))
            final char[]value = this.value;
            for (inti =fromIndex;i <max;i++) {
                if (value[i] == ch) {
                    return i;
                }
            }
            return -1;
        } else {
            return indexOfSupplementary(ch,fromIndex);
        }

    }

ch< Character.MIN_SUPPLEMENTARY_CODE_POINT 这个条件非常重要,是分界BmpCode的界限。Character.MIN_SUPPLEMENTARY_CODE_POINT是java中的16进制的表示方式,以0x开头代表十六进制,0开头的是八进制。

Character.MIN_SUPPLEMENTARY_CODE_POINT这个数代表十进制中62355,刚好是2个字节。

 

非BmpCode代码点是ValidCodePoint代码点的索引位置方法indexOfSupplementary(intch,intfromIndex)

源码:private int indexOfSupplementary(intch,int fromIndex) {
        if (Character.isValidCodePoint(ch)) {
            final char[]value = this.value;
            final char hi = Character.highSurrogate(ch);
            final char lo = Character.lowSurrogate(ch);
            final int max =value.length- 1;
            for (inti =fromIndex;i <max;i++) {
                if (value[i] == hi &&value[i+ 1] ==lo) {
                    return i;
                }
            }
        }
        return -1;

    }

int类型在java中占4个字节,非BmpCode代码点是ValidCodePoint代码点是有高两位和低两位,这种类型的int转化为字符时分开来处理,作为两个字符

 

 

String的intern( )方法分析:

这个方法是本地方法,原理是:String的intern()方法的原理,在调用此方法时候会初始化一个空的字符串池,然后将该字符串对象加入该池中,当再次调用这个方法的时候,会判断这个池中是否包含字符串,如果包含则从池中返回这个字符串,否则加入这个字符串并返回这个字符串对象的引用。

测试代码和输出结果是:

publicstaticvoid testIntern(){
System.out.println("\n测试字符串转的本地方法intern()的原理:");
String str =new String("abc");
String str0 =str.intern();
System.out.println(str == str0);
String str1=str.intern();
System.out.println(str0 == str1);
String str2 =new String("abc");
String str3 =str2.intern();
System.out.println(str0 == str3);
System.out.println("测试字符串转的本地方法intern()的原理结束\n");

 }

测试字符串转的本地方法intern()的原理:
false
true
true

测试字符串转的本地方法intern()的原理结束

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于Java String类的replace方法,其源码如下: ``` public String replace(char oldChar, char newChar) { if (oldChar != newChar) { int len = value.length; int i = -1; char[] val = value; /* avoid getfield opcode */ while (++i < len) { if (val[i] == oldChar) { break; } } if (i < len) { char buf[] = new char[len]; for (int j = 0; j < i; j++) { buf[j] = val[j]; } while (i < len) { char c = val[i]; buf[i] = (c == oldChar) ? newChar : c; i++; } return new String(buf, true); } } return this; } ``` 这个方法用于将字符串中的一个字符替换成另一个字符,并返回新的字符串。我们来逐行分析一下它的源码: 1. 如果要替换的字符和替换后的字符相同,则直接返回原字符串。 ``` if (oldChar != newChar) { ``` 2. 获取字符串的长度和字符数组。 ``` int len = value.length; char[] val = value; /* avoid getfield opcode */ ``` 3. 在字符数组中查找要替换的字符。 ``` int i = -1; while (++i < len) { if (val[i] == oldChar) { break; } } ``` 4. 如果找到了要替换的字符,则将其替换为新字符,否则直接返回原字符串。 ``` if (i < len) { char buf[] = new char[len]; for (int j = 0; j < i; j++) { buf[j] = val[j]; } while (i < len) { char c = val[i]; buf[i] = (c == oldChar) ? newChar : c; i++; } return new String(buf, true); } ``` 5. 如果要替换的字符不存在,则直接返回原字符串。 ``` return this; ``` 总体来说,这个方法的实现比较简单,就是遍历字符数组,找到要替换的字符,然后再将其替换成新字符,最后返回新的字符串。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值