<jdk>【源码解析】java.lang.StringBuilder#reverse方法-反转字符串

1,305 阅读3分钟

导读

reverse方法,直译过来就是反转的意思,在StringBuilder类中的reverse方法,代表将当前StringBuilder中的字符串进行反转,例如字符串"abcde"反转后变成"edcba",那么该方法底层是怎么实现的呢?

源码

java.lang.StringBuilder#reverse:

    @Override
    public StringBuilder reverse() {
        super.reverse();
        return this;
    }

方法中没有做特殊处理,直接调用了父类AbstractStringBuilder中的reverse方法,其源码如下

java.lang.AbstractStringBuilder#reverse:

public AbstractStringBuilder reverse() {
        boolean hasSurrogates = false;
        int n = count - 1;
        for (int j = (n-1) >> 1; j >= 0; j--) {
            int k = n - j;
            char cj = value[j];
            char ck = value[k];
            value[j] = ck;
            value[k] = cj;
            if (Character.isSurrogate(cj) ||
                Character.isSurrogate(ck)) {
                hasSurrogates = true;
            }
        }
        if (hasSurrogates) {
            reverseAllValidSurrogatePairs();
        }
        return this;
    }

我们分层级进行解析:

1.初始化变量

初始化boolean类型变量hasSurrogates,代表是否存在增补字符对,增补字符对的概念 初始化数组右边界的角标n,等于字符串长度count-1,count为类的成员变量

2.遍历交换元素

循环初始化条件:int j = (n-1) >> 1; 注意这里是从(n-1)/2开始,以n=8为例,字符串有9个字符,第5个字符无需交换,从第四个字符开始即可,即从角标3开始向下遍历;若从n/2开始,即角标4,就会多一次对于第5个字符的无效循环过程 循环内部逻辑: 交换j位置和n-j位置的元素,并且逐个字符进行判断,如果存在某个字符是增补字符对中的字符,则将hasSurrogates标识置为true

3.处理增补字符对

如果字符串中存在增补字符对,则需要针对增补字符对进行特殊处理

4.返回结果

增补字符对

在java中,一个char类型占用16个bit位,所以单纯的char类型应该可以表示2 ^ 16个字符,即65536,但是utf包含的字符是多于65536个,那么多出来的字符应该如何表示呢?
unicode标准制定组想到的方法是使用连续两个char代表某两个char的组合,即所谓的【增补字符对】,英文名叫surrogatePairs

那么,拿到一个char,如何确定其代表的是一个char,还是增补字符对中的一个元素呢?
这里就有一套规范,规定U+D800 至 U+DBFF 的字符为上对(high surrogate)共1024个,规定U+DC00 至 U+DFFF为下对(low surrogate)也是1024个,并且严格规定上对必须出现在下对之前,这样的连续char类型代表增补字符对。

在字符串反转中,经历遍历之后,上下对的位置会进行交换,变为了下上对,这样是无法解析的,所以,如果被反转的字符串中包含了增补字符对,需要再进行一次循环,将初步反转后的字符串里面的增补字符对的背部顺序调整正确,代码如下

java.lang.AbstractStringBuilder#reverseAllValidSurrogatePairs

private void reverseAllValidSurrogatePairs() {
        for (int i = 0; i < count - 1; i++) {
            char c2 = value[i];
            if (Character.isLowSurrogate(c2)) {
                char c1 = value[i + 1];
                if (Character.isHighSurrogate(c1)) {
                    value[i++] = c1;
                    value[i] = c2;
                }
            }
        }
    }

总结

就此,我们完整的阅读了StringBuilder的reverse方法的源码,内部调用父类的reverse方法,值得一提的是,该方法同样被StringBuffer的reverse方法调用,做到复用。
在反转方法中,注意循环的开始条件是(n-1)>>2,避免了中间元素的无效循环。
同时,我们学习了增补字符对的设计,也正是因为增补字符对的存在,我们可能需要多一次循环来处理因为反转产生的无效增补字符对。

原创不易,希望大家读后可以有所收获~

^-^转载请标明出处哦^-^