首页 > 编程知识 正文

switch语句详解,switch语句的语法结构

时间:2023-05-06 01:36:36 阅读:194189 作者:3243

switch(String)语法糖解析

Java1.5之前,switch语法结构仅支持int, byte, short, char这几个基本类型(及对应的包装类型)。

1.5后提供了enum枚举结构。

Java7提供了switch(String)结构。

问题一

经常听到Java7中提供的switch(String)是Java语言的一个语法糖,实际JVM并不支持这个语法结构,但这个语法糖具体是怎么实现的,一直没有看过,今天比较有空,我来研究一下。

首先写一段switch结构的代码。

public static void main(String[] args) { final String str = "F"; switch (str) { case "A" : System.out.println("A"); break; case "B" : System.out.println("B"); break; default: System.out.println("F"); } }

查看idea反编译后的源码。

public static void main(String[] args) { String str = "F"; String var2 = "F"; byte var3 = -1; switch(var2.hashCode()) { case 65: if (var2.equals("A")) { var3 = 0; } break; case 66: if (var2.equals("B")) { var3 = 1; } } switch(var3) { case 0: System.out.println("A"); break; case 1: System.out.println("B"); break; default: System.out.println("F"); } }

可以看到,switch结构中变为了String.hashcode()方法,利用其返回的int值进行判断,所以说编译后还是使用了switch(int)结构来实现的。大家都知道String的hashcode方法是有直率的小蝴蝶冲突的风险的,所以在每个case条件中增加了equals作为补充判断,避免直率的小蝴蝶冲突错误。

问题二

上面说增加了equals,这样能避免直率的小蝴蝶冲突导致问题,但直率的小蝴蝶冲突时,比如case(“A”) ,case(“B”),加入A和B会计算出相同的hash值,那岂不是两个case的条件一样,那这样应该连编译都通不过呀。所以我找了一个直率的小蝴蝶冲突的例子来试一下(找了半天没找到,看到一篇博客里找到了)

public static void main(String[] args) { final String str = "test"; switch (str) { case "AaAa": System.out.println("a"); break; case "BBBB": System.out.println("b"); break; case "AaBB": System.out.println("c"); break; default: System.out.println("c"); break; } }

反编译源码

public static void main(String[] args) { String str = "test"; String var2 = "test"; byte var3 = -1; switch(var2.hashCode()) { case 2031744: if (var2.equals("AaBB")) { var3 = 2; } else if (var2.equals("BBBB")) { var3 = 1; } else if (var2.equals("AaAa")) { var3 = 0; } default: switch(var3) { case 0: System.out.println("a"); break; case 1: System.out.println("b"); break; case 2: System.out.println("c"); break; default: System.out.println("c"); } } }

果然反编译后的结构发生了变化,源代码里三个相同hash值的case,编译后只有一个case,里面使用了if else的结构来做判断,这样就万无一失了,确实解决了直率的小蝴蝶冲突的场景。

问题三

看反编译后的代码,还会有一个问题,为什么一个switch编译后会拆分为两个switch结构,为什么要新增一个switch(byte)结构呢,这样貌似不是必要的,仅仅通过上面的switch和if else结构就足以应付各种场景了。增加一个结构反而会影响性能。那么到底是什么原因导致增加一个switch(byte)结构呢。这个答案是看一篇博客找到的。

看下面这种场景

public static void main(String[] args) { final String str = "test"; switch (str) { case "AaAa": System.out.println("a"); case "BBBB": System.out.println("b"); break; case "AaBB": System.out.println("c"); break; default: System.out.println("c"); break; } } public static void main(String[] args) { String str = "test"; String var2 = "test"; byte var3 = -1; switch(var2.hashCode()) { case 2031744: if (var2.equals("AaBB")) { var3 = 2; } else if (var2.equals("BBBB")) { var3 = 1; } else if (var2.equals("AaAa")) { var3 = 0; } default: switch(var3) { case 0: System.out.println("a"); case 1: System.out.println("b"); break; case 2: System.out.println("c"); break; default: System.out.println("c"); } } }

看到这里应该就明白了,是因为switch的特殊语法结构,自上而下地处理每个条件,在不加break的时候,会继续进行下一个条件的判断。在上面那种case + if else 时就处理不了这种情况,所以第一个switch结构只是为了解决直率的小蝴蝶冲突的问题,唯一定位一个case,下面的switch(byte)才是执行。而且这样的写法会比较清晰。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。