资讯专栏INFORMATION COLUMN

原来你是这样的switch~

freewolf / 754人阅读

摘要:对支持的实现原理感兴趣的原因,是在跟组员探讨线上的一个空指针异常来的,以前根本没意识到小小的还有这样的玩法。这里我们定义参数,根据值跳转不同的逻辑。在我看来,代码的脆弱多数是研发人员的代码风格不规范导致。

在 switch-case 语句的条件判断中,或许使用整形或者枚举更好,但由于种种历史原因,项目中已大量使用字符串的情况下,只得硬着皮头往前冲了。对 switch 支持 String 的实现原理感兴趣的原因,是在跟组员探讨线上的一个空指针异常来的,以前根本没意识到小小的switch 还有这样的玩法。

要对 switch 的原理追根溯源,我们来写一段简单的 switch 代码,反编译来看看字节码层是什么效果。

public class Testk {
    public static void main(String[] args) {
        String key = null;
        switch (key) {
            case "java":
                System.out.println("caught java");
                break;
            case "android":
                System.out.println("caught android");
                break;
        }
    }
}

这里我们定义参数key,根据 key 值跳转不同的 case 逻辑。

正常情况下,使用 “javac <.java> ”生成.class 文件,使用“javap -verbose <.class>”即可得到字节码,但由于javap得到的字节码结构难以理解,这里我们使用 JD-Gui 工具来查看。

Mac 下安装JD-Gui工具

brew cask install jd-gui

把*.class 文件拖入打开的 JD-Gui窗口,即可得到如下结果:

import java.io.PrintStream;

public class Testk
{
  public static void main(String[] paramArrayOfString)
  {
    Object localObject1 = null;
    Object localObject2 = localObject1;int i = -1;
    switch (((String)localObject2).hashCode())
    {
    case 3254818: 
      if (((String)localObject2).equals("java")) {
        i = 0;
      }
      break;
    case -861391249: 
      if (((String)localObject2).equals("android")) {
        i = 1;
      }
      break;
    }
    switch (i)
    {
    case 0: 
      System.out.println("caught java");
      break;
    case 1: 
      System.out.println("caught android");
    }
  }
}

通过编译后的代码,我们知道 switch 处理字符串是先获取hashCode ->equals()来实现的。

看到这里,我们明白文首的空指针是怎么来的了,编译器针对 switch 的 String 做编译处理时, 需要针对 key 做做非空校验
另外,这里先基于 hashCode()再 equals()方法进行安全检查是有必要的,用来避免 hash 碰撞。

网上很多人都不建议使用字符串,给出的理由多半是String 的大小写使得代码更脆弱。在我看来,代码的脆弱多数是研发人员的代码风格不规范导致。
就拿上面的代码片段来说,改成全局定义变量即可解决大小写敏感问题。

public class Testk {
    private static final String KEY_JAVA=“java”;
    private static final String KEY_ANDROID=“android”;

    public static void main(String[] args) {
        String key = null;
        switch (key) {
            case KEY_JAVA:
                System.out.println("caught java");
                break;
            case KEY_ANDROID:
                System.out.println("caught java");
                break;
        }
    }
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/72345.html

相关文章

  • 嘻哈说:设计模式之单一职责原则

    摘要:定义首先呢,我们来看一下单一职责原则的定义。只负责一项职责,这就是单一职责原则。这时候就涉及到平衡的问题,平衡单一职责原则与修改造成的开销。嘻哈说接下来,请您欣赏单一职责原则的原创歌曲。 showImg(https://segmentfault.com/img/remote/1460000016523263?w=600&h=350); 1、定义 首先呢,我们来看一下单一职责原则的定义。...

    Leo_chen 评论0 收藏0
  • 网络协议 终章 - GTP 协议:复杂移动网络

    摘要:网络协议解析我们来仔细看一下网络的协议,真的非常复杂。控制面协议其中虚线部分是控制面的协议。这也是传输层的协议,也是面向连接的,但是更加适合移动网络。第二端是从到,通过协议知道自己是其中一端,并主动通过协议,告诉它是隧道的另一端。 前面都是讲电脑上网的情景,今天我们就来认识下使用最多的移动网络上网场景。 移动网络的发展历程     你一定知道手机上网有 2G、3G、4G 的说法,究竟这...

    张巨伟 评论0 收藏0
  • FSM状态机之状态模式

    摘要:要注意这里的一个状态行为因为这个词是状态模式中最重要的个概念。考虑到这点,聪明的在中推出了状态机这个伪函数,能够帮助我们快速实现状态化。这里就引入了状态机这个概念,以及和他对应的状态表。  首先声明一点,这个模式是我目前见过最好用(本人观点),但是也是最难理解的一个(本人观点)。 所以大家需要做好心理准备,如果,对这个模式没有特别强烈的需求,比如: 我有一个Button,我按次数点击它...

    k00baa 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<