Java switch关键字原理及用法详解

作者:逸游Java 时间:2023-04-16 23:29:49 

这篇文章主要介绍了Java中 switch关键原理及用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

Switch语法

switch作为Java内置关键字,却在项目中真正使用的比较少。关于switch,还是有那么一些奥秘的。

要什么switch,我有if-else

确实,项目中使用switch比较少的一个主要原因就在于它的作用能被if-else代替,况且switch对类型的限制,也阻碍了switch的进一步使用。

先看看switch的语法:


switch(exp){
case exp1:
 break;
case exp2:
 break;
default:
 break;
}

其中exp的类型限制为:byte ,short , int , char,及其包装类,以及枚举和String(JDK1.7)

为什么要有这些限制?

如果说,switch的功能和if-else的一模一样,那么它存在的意义在哪里?

答案是:switch和if-else在设计的时候,是有一定的性能差别的。

看代码:


public class Test {
public static void switchTest(int a) {
 switch (a) {
  case 1:
   System.out.println("1");
   break;
  case 2:
   System.out.println("2");
   break;
  default:
   System.out.println("3");
   break;
 }
}
}

javap -c Test.class

结果如下:


public static void switchTest(int);
Code:
 0: iload_0
 1: lookupswitch { // 2
     1: 28
     2: 39
   default: 50
  }

...

这里面省略一些代码。

可以发现,switch是通过lookupswitch指令实现。那么lookupswitch指令是干嘛的呢?

在Java se8文档中的描述可以大概知道:

switch可以被编译为两种指令

  • lookupswitch:当switch的case比较稀疏的时候,使用该指令对int值的case进行一一比较,直至找到对应的case(这里的查找,可以优化为二分查找)

  • tableswitch:当switch的case比较密集的时候,使用case的值作为switch的下标,可以在时间复杂度为O(1)的情况下找到对应的case(可以类比HashMap)

并且文档中还有一段描述:

Java虚拟机的tableswitch和 lookupswitch指令仅对int数据有效。因为对 byte,char或或short值的操作在内部被提升为int,所以对其switch表达式求值为其中一个类型进行编译,就好像它被计算为要键入一样int。如果 chooseNear方法是使用type编写的,则使用类型时 short将生成相同的Java虚拟机指令int。其他数字类型必须缩小到类型int 以便在a中使用switch。

现在,我们应该能够明白,为什么switch关键字会有类型限制了,因为 switch所被翻译的关键字是被限制为int类型的,至于为什么是int,我猜应该是基于性能和实现的复杂度的考量吧。

int之外的类型

我们明白了byte,shor,char,int能被作为switch类型后,再看看枚举和String


public static void switchTest(String a) {
 switch (a) {
  case "1":
   System.out.println("1");
   break;
  case "2":
   System.out.println("2");
   break;
  default:
   System.out.println("3");
   break;
 }
}

编译生成Test.class。拖入IDEA进行反编译得到如下代码:


public static void switchTest(String a) {
 byte var2 = -1;
 switch(a.hashCode()) {
 case 49:
  if (a.equals("1")) {
   var2 = 0;
  }
  break;
 case 50:
  if (a.equals("2")) {
   var2 = 1;
  }
 }
 switch(var2) {
 case 0:
  System.out.println("1");
  break;
 case 1:
  System.out.println("2");
  break;
 default:
  System.out.println("3");
 }
}

可以看见,JDK7 所支持的String类型是通过获取String的hashCode来进行选择的,也就是本质上还是int.为什么String可以这样干?这取决于String是一个不变类。

为了防止hash碰撞,代码更加保险的进行了equals判断。

再来看看Enum


public static void switchTest(Fruit a) {
switch (a) {
 case Orange:
  System.out.println("Orange");
  break;
 case Apple:
  System.out.println("Apple");
  break;
 default:
  System.out.println("Banana");
  break;
}
}

编译生成Test.class。拖入IDEA进行反编译得到如下代码:


public static void switchTest(Fruit a) {
 switch(1.$SwitchMap$com$dengchengchao$Fruit[a.ordinal()]) {
 case 1:
  System.out.println("Orange");
  break;
 case 2:
  System.out.println("Apple");
  break;
 default:
  System.out.println("Banana");
 }
}

可以看到,枚举支持switch更加简单,直接通过枚举的顺序即可作为相关case

总之:

switch的设计按道理来说,是比if-else要快的,但是在99.99%的情况下,他们性能差不多,除非case分支量巨大,但是在case分支过多的情况下,一般应该考虑使用多态重构了。

switch虽然支持byte,int,short,char,enum,String但是本质上都是int,其他的只是编译器帮你进行了语法糖优化而已。

来源:https://www.cnblogs.com/dengchengchao/p/11831231.html

标签:java,switch,关键字
0
投稿

猜你喜欢

  • Spring存储与读取Bean对象方法

    2021-11-12 03:35:27
  • 浅谈一下Java的双亲委派模式

    2021-11-12 02:48:17
  • Android中使用CircleImageView和Cardview制作圆形头像的方法

    2022-04-19 05:41:35
  • SpringBoot中实现分布式的Session共享的详细教程

    2023-08-23 18:23:43
  • opencv3/C++ FLANN特征匹配方式

    2021-08-19 10:17:47
  • Android Studio导入jar包过程详解

    2023-01-02 08:04:51
  • SpringBoot使用Jackson配置全局时间日期格式

    2021-10-04 12:45:06
  • Android不显示开机向导和开机气泡问题

    2022-10-13 23:56:26
  • Javaweb获取表单数据的多种方式

    2022-12-25 18:13:41
  • Android 自定义 Toast 显示时间

    2022-01-22 23:22:06
  • Andriod studio 打包aar 的方法

    2023-12-13 19:32:36
  • Spring Cloud 的 Hystrix.功能及实践详解

    2023-11-19 06:40:46
  • C语言数据结构系列篇二叉树的遍历

    2023-12-28 03:19:03
  • SpringBoot线程池和Java线程池的使用和实现原理解析

    2022-06-27 07:22:30
  • Lombok基本注解之@SneakyThrows的作用

    2021-12-24 15:30:47
  • 浅谈Java多线程实现及同步互斥通讯

    2022-11-17 17:50:53
  • 详解Java中的迭代迭代器Iterator与枚举器Enumeration

    2021-08-21 19:32:44
  • SpringSecurity注销设置的方法

    2023-08-05 20:46:15
  • Java Swing JProgressBar进度条的实现示例

    2023-07-15 17:48:47
  • Java回调方法详解

    2022-09-25 08:33:54
  • asp之家 软件编程 m.aspxhome.com