java switch是如何支持String类型的?

我们知道自java 1.7以后, java switch开始支持String类型。那有没有同学思考过,java是如何支持String类型的?

我们看下面这段代码:

public class SwitchString {
    public static void main(String[] args) {
        switch (args[0]) {
        case "A" : break;
            case "B" : break;
            default :
    }//switch
    }
}
在JDK1.8.0_152的环境下,我们使用javac编译SwicthString.java这个源文件。得到了SwitchString.class这个字节码文件。而后我们利用javap反编译SwitchString.class文件。得到下图的结果(我直接截取的main方法的反编译结果):

图中,我用蓝色线,圈起来的部分,出现了,65, 66字样,而在上面又出现了,String的hashCode方法。我们知道很多高级语言的,像C,C++都是自switch诞生以来,便支持int类型的,java也不例外。String的hashCode方法返回的便是其int成员变量hash。而65则是字符'A'的ASCII码,66是字符'B'的ASCII码。同时65也是String类型"A"的hash值,66也是String类型的"B"的hash值。

我们是不是可以猜测,JVM就是用String的hash值这一特性,来使switch支持String类型的。

大胆假设,小心求证。我们借助IDEA反编译SwitchString.class字节码文件。得到下面这份直观的反编译结果。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
 
public class SwitchString {
    public SwitchString() {
    }
 
    public static void main(String[] var0) {
        String var1 = var0[0];
        byte var2 = -1;
        switch(var1.hashCode()) {
        case 65:
            if (var1.equals("A")) {
                var2 = 0;
            }
            break;
        case 66:
            if (var1.equals("B")) {
                var2 = 1;
            }
        }
 
        switch(var2) {
        case 0:
        case 1:
        default:
        }
    }
}
通过这份直观的结果,我们知道了jvm是先调用String的hashCode方法得到hash值,然后将case中的常量换掉。但是有个很奇怪的地方,为什么在case中,还要再使用String的equals方法呢?这就和String的hashCode计算hash值有关了。我附上JDK1.8.0_152中关于String的hashCode计算方法:

    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;
 
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }
读者如果阅读过String的源码,就会知道这样,String的Hash可能会冲突,即两个不同的String可能计算出相同的hash值。

也因此JVM才会又用String的equals方法再次比较,并且在下面又增加了一个Switch-byte结构。

【总结】:java中switch支持String,是利用String的hash值,本质上是switch-int结构。并且利用到了equals方法来防止hash冲突的问题。最后利用switch-byte结构,精确匹配。

【思考】:string的hash冲突,在其他数据结构中,如HashMap<String, T>, HashSet<String>中是如何解决的?两个switch结构,下面那个一定会是switch-byte结构吗?
 

猜你喜欢

转载自blog.csdn.net/qq_41815015/article/details/88073238
今日推荐