java字符串compareTo源码解析

字符串compareTo源码解析

这个方法的源码需要参考三个java文件,即String.java ,StringUTF16.java ,StringLatin1.java
JDK9之后由byte类型的数组来存储String,维护了一个属性coder,它是一个编码格式的标识,使用LATIN1还是UTF-16,这个是在String生成的时候自动的,如果字符串中都是能用LATIN1就能表示的就是0,否则就是UTF-16.

private final byte[] value;
private final byte coder;

String类的compareTo方法如下:

public int compareTo(String anotherString) {
        byte v1[] = value;
        byte v2[] = anotherString.value;
        byte coder = coder();//返回字符串编码方式LATIN1或者UTF16
        if (coder == anotherString.coder()) {
            return coder == LATIN1 ? StringLatin1.compareTo(v1, v2)
                                   : StringUTF16.compareTo(v1, v2);
        }
        return coder == LATIN1 ? StringLatin1.compareToUTF16(v1, v2)
                               : StringUTF16.compareToLatin1(v1, v2);
     }

编码方式不同,则比较的方法也不同。LATIN1的编码是一个字节存储一个字符,UTF16是两个字节存储一个字符。

编码方式都是LATIN1

在字符串compareTo的时候,如果两个字符串的编码方式都是LATIN1,则调用StringLatin1.compareTo(v1, v2)(v1, v2是两个字节数组)

public static int compareTo(byte[] value, byte[] other, int len1, int len2) {
    int lim = Math.min(len1, len2);//在较短的长度范围内比较
    for (int k = 0; k < lim; k++) {
        if (value[k] != other[k]) {
            return getChar(value, k) - getChar(other, k);//执行到return的时候,循环自动退出。
        }
    }
    return len1 - len2;//如果前几位都相同,则会返回长度差
}

getChar函数返回的是什么值呢?

public static char getChar(byte[] val, int index) {
    return (char)(val[index] & 0xff);//保证val[index]低8位不变,高位补0,是为了保值。
}

可以看出getChar最后输出的是一个字符。
而getChar函数相减返回两个字符ascii十进制表示的差值。

ascii值表如下:https://blog.csdn.net/weixin_44893585/article/details/103068265

编码方式都是UTF-16

编码方式都是UTF-16,则调用StringUTF16.compareTo(v1, v2)
与StringLatin1.compareTo的方法是一样的,只是getChar不一样

static char getChar(byte[] val, int index) {
    assert index >= 0 && index < length(val) : "Trusted caller missed bounds check";
    index <<= 1;//首先左移一位,索引x2,因为两个字节代表一个字符
    return (char)(((val[index++] & 0xff) << HI_BYTE_SHIFT) |
                  ((val[index]   & 0xff) << LO_BYTE_SHIFT));
}

如果是UTF-16编码,取一个char,把index乘以2,再把连续的两个字节拼在一起就行了,这里因为是两个字节拼成char,涉及到了大小端问题,所以做了特殊处理。

static final int HI_BYTE_SHIFT;
static final int LO_BYTE_SHIFT;
static {
    if (isBigEndian()) {//如果是大端
        HI_BYTE_SHIFT = 8;
        LO_BYTE_SHIFT = 0;
    } else {//如果是小端
        HI_BYTE_SHIFT = 0;
        LO_BYTE_SHIFT = 8;
    }
}
private static native boolean isBigEndian();

(native关键字表示这个方法不是java实现的,那么就不是原生态方法,也就不会存在这个文件中。开发java语言的时候用到,native关键字是与c++联合开发的时候,使java控制底层的,比如内存。)

字符串的编码方式不同

如果字符串的编码方式不同,调用不同编码类型字符串的比较方法

Latin1和UTF16相比

StringLatin1.compareToUTF16(v1, v2)

private static int compareToUTF16Values(byte[] value, byte[] other, int len1, int len2) {
    int lim = Math.min(len1, len2);
    for (int k = 0; k < lim; k++) {
        char c1 = getChar(value, k);
        char c2 = StringUTF16.getChar(other, k);
        if (c1 != c2) {
            return c1 - c2;//如果不相等,则返回ASCII字符对应的十进制的差值
        }
    }
    return len1 - len2;//如果前几位都相等,则两个字符串长度之差。
}
UTF16和Latin1相比
StringUTF16.compareToLatin1(v1, v2)

这个函数的返回值是:-StringLatin1.compareToUTF16(other, value, len2, len1)
即StringLatin1.compareToUTF16的返回值取反

结果是字符串compareTo函数返回的是ASCII字符对应的十进制的差值或者字符串长度之差。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值