java中的switch执行原理

switch可以进行跳转优化,java中对switch有两种处理方式,生成不同的jvm指令,一是tableswitch,一个是lookupswitch.
对于case的分支比较密集的情况,如
Java code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public  class  Test {
 
     public  static  void  main(String[] args) {
         int  i =  3 ;
         switch  (i) {
             case  0 :
                 System.out.println( "0" );
                 break ;
             case  1 :
                 System.out.println( "1" );
                 break ;
             case  3 :
                 System.out.println( "3" );
                 break ;
             case  5 :
                 System.out.println( "5" );
                 break ;
             case  10 :
                 System.out.println( "10" );
                 break ;
             case  13 :
                 System.out.println( "13" );
                 break ;
             case  14 :
                 System.out.println( "14" );
                 break ;
         default :
         System.out.println( "default" );
                 break ;
         }
 
 
     }
}

使用tableswitch,得到
Java code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public  static  void  main(java.lang.String[]);
   Code:
    0 :    iconst_3
    1 :    istore_1
    2 :    iload_1
    3 :    tableswitch{  //0 to 14
         0 76 ;
         1 87 ;
         2 153 ;
         3 98 ;
         4 153 ;
         5 109 ;
         6 153 ;
         7 153 ;
         8 153 ;
         9 153 ;
         10 120 ;
         11 153 ;
         12 153 ;
         13 131 ;
         14 142 ;
         default 153  }
    76 :    getstatic    # 2 //Field java/lang/System.out:Ljava/io/PrintStream;
    79 :    ldc    # 3 //String 0
    81 :    invokevirtual    # 4 //Method java/io/PrintStream.println:(Ljava/lang/String;)V
    84 :    goto    161
    87 :    getstatic    # 2 //Field java/lang/System.out:Ljava/io/PrintStream;
    90 :    ldc    # 5 //String 1
    92 :    invokevirtual    # 4 //Method java/io/PrintStream.println:(Ljava/lang/String;)V
    95 :    goto    161
    98 :    getstatic    # 2 //Field java/lang/System.out:Ljava/io/PrintStream;
    101 :    ldc    # 6 //String 3
    103 :    invokevirtual    # 4 //Method java/io/PrintStream.println:(Ljava/lang/String;)V
    106 :    goto    161
    109 :    getstatic    # 2 //Field java/lang/System.out:Ljava/io/PrintStream;
    112 :    ldc    # 7 //String 5
    114 :    invokevirtual    # 4 //Method java/io/PrintStream.println:(Ljava/lang/String;)V
    117 :    goto    161
    120 :    getstatic    # 2 //Field java/lang/System.out:Ljava/io/PrintStream;
    123 :    ldc    # 8 //String 10
    125 :    invokevirtual    # 4 //Method java/io/PrintStream.println:(Ljava/lang/String;)V
    128 :    goto    161
    131 :    getstatic    # 2 //Field java/lang/System.out:Ljava/io/PrintStream;
    134 :    ldc    # 9 //String 13
    136 :    invokevirtual    # 4 //Method java/io/PrintStream.println:(Ljava/lang/String;)V
    139 :    goto    161
    142 :    getstatic    # 2 //Field java/lang/System.out:Ljava/io/PrintStream;
    145 :    ldc    # 10 //String 14
    147 :    invokevirtual    # 4 //Method java/io/PrintStream.println:(Ljava/lang/String;)V
    150 :    goto    161
    153 :    getstatic    # 2 //Field java/lang/System.out:Ljava/io/PrintStream;
    156 :    ldc    # 11 //String default
    158 :    invokevirtual    # 4 //Method java/io/PrintStream.println:(Ljava/lang/String;)V
    161 :    return
 
}

从中可以看到tableswitch使用的跳转表。它这样查找,如果case值不在//0 to 14之间,直接执行default,如果在此范围之内,则取目标值-0这一项作为目标,比如switch(i),i为3,则跳转到3-0=3,使用数组中的第三项作为目标,也就是3: 98;直接去执行98行。

如果case中的值比较稀疏,则使用lookupswitch:
Java code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public  class  Test2 {
 
     public  static  void  main(String[] args) {
         int  i =  3 ;
         switch  (i) {
             case  3 :
                 System.out.println( "3" );
                 break ;
             case  20 :
                 System.out.println( "20" );
                 break ;
             case  50 :
                 System.out.println( "50" );
                 break ;
             case  100 :
                 System.out.println( "100" );
                 break ;
         }
 
 
     }
}

编译为
Java code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public  static  void  main(java.lang.String[]);
   Code:
    0 :    iconst_3
    1 :    istore_1
    2 :    iload_1
    3 :    lookupswitch{  //4
         3 44 ;
         20 55 ;
         50 66 ;
         100 77 ;
         default 85  }
    44 :    getstatic    # 2 //Field java/lang/System.out:Ljava/io/PrintStream;
    47 :    ldc    # 3 //String 3
    49 :    invokevirtual    # 4 //Method java/io/PrintStream.println:(Ljava/lang/String;)V
    52 :    goto    85
    55 :    getstatic    # 2 //Field java/lang/System.out:Ljava/io/PrintStream;
    58 :    ldc    # 5 //String 20
    60 :    invokevirtual    # 4 //Method java/io/PrintStream.println:(Ljava/lang/String;)V
    63 :    goto    85
    66 :    getstatic    # 2 //Field java/lang/System.out:Ljava/io/PrintStream;
    69 :    ldc    # 6 //String 50
    71 :    invokevirtual    # 4 //Method java/io/PrintStream.println:(Ljava/lang/String;)V
    74 :    goto    85
    77 :    getstatic    # 2 //Field java/lang/System.out:Ljava/io/PrintStream;
    80 :    ldc    # 7 //String 100
    82 :    invokevirtual    # 4 //Method java/io/PrintStream.println:(Ljava/lang/String;)V
    85 :    return

可以看到其中的
 3: lookupswitch{ //4
3: 44;
20: 55;
50: 66;
100: 77;
default: 85 }
这个就要挨着查表确定跳转位置了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 虚拟机面试题全面解析,《深入理解Java虚拟机》干货版,自己总结,希望能够帮助大家,免费下载~什么是类加载机制? 虚拟机和物理机的区别是什么? 运行时栈帧结构 Java方法调用 什么是方法调用? Java的方法调用,有什么特殊之处? Java虛拟机调用字节码指令有哪些? 虚拟机是如何执行方法里面的字节码指令的? 解释执行 基于栈的指令集和基于寄存器的指令集 什么是基于栈的指令集? 什么是基于寄存器的指令集? 基于栈的指令集的优缺点? Javac编译过程分为哪些步骤? 什么是即时编译器? 解释器和编译器 为什么要采用分层编译? 分层编译器有哪些层次? 编译对象与触发条件 热点代码有哪些? 如何判断一段代码是不是热点代码? Hotspot虚拟机使用第二种,有两个计数器: 方法调用计数器统计方法 有哪些经典的优化技术(即时编译器)? 公共子表达式消除 数组边界检查消除 方法内联 逃逸分析 如果对象不会逃逸到方法或线程外,可以做什么优化? Java与C/C++的编译器对比 物理机如何处理并发问题? Java内存模型 什么是Java内存模型? Java内存模型的目标? 主内存与工作内存 内存间的交互操作 原子性、可见性、有序性 volatile 什么是 volatile? 为什么基于 volatile变量的运算在并发下不一定是安全的? 为什么使用 volatile? 并发与线程 并发与线程的关系? 什么是线程? 实现线程有哪些方式? Java线程的实现 Java线程调度 什么是线程调度? 线程调度有哪些方法? 线程安全的定义? Java语言操作的共享数据,包括哪些? 不可变 如何实现线程安全? 阻塞同步(互斥同步) 非阻塞同步 锁优化是在DK的那个版本? 为什么要提出自旋锁? 自旋锁的原理? 自旋的缺点? 什么是自适应自旋? 锁消除 锁粗化 轻量级锁 偏向锁 JDK是什么? JDK是用于支持Java程序开发的最小环境。 1.Java程序设计语言 2.Java虚拟机 3. Java ap类库 JRE是什么? JRE是支持Java程序运行的标准环境。 1. Java SE aPi子集 2.Java虚拟机 Java历史版本的特性? Java∨ ersion se5.0 引入泛型; 增强循环,可以使用迭代方式; 自动装箱与自动拆箱; 类型安全的枚举 ·可变参数; 静态引入 元数据(注解); 引入 Instrumentation Java∨ ersion se6 支持脚本语言 引入JDBC40API; 引入 Java Compiler API; 可插拔注解; 增加对 Native PKi( Public Key Infrastructure)、 Java gss( Generic Security Service) Kerberos和 LDAP(Lightweight Directory Access Protocol的支持; 继承 Web services 做了很多优化。 Java∨ ersion se7 switch语句块允许以字符串作为分支条件; 在创建泛型对象时应用类型推断 ·在一个语句块捕获多种异常; ·支持动态语言; 支持try-with- resources 引入 Java nio.2开发包; ·数值类型可以用2进制字符串表示,并且可以在字符串表示添加下划线; 钻石型语法; nu值的自动处理。 Java 8 函数式接口 Lambda表达式 接口的增强 运行时数据区域包括哪些? 1.程序计数器 2.Java虚拟机栈 3.本地方法栈 4.Java堆 5.方法区 6.运行时常量池 7.直接内存 程序计数器(线程私有) 程序计数器( Program Counter Register)是一块较小的内存空间,可以看作是当前线程所 执行字节码的行号指示器。分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这 个计数器完成。 由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式实现的。为了线 程切换后能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器,各线程之间的计 数器互不影响,独立存储。 1.如果线程正在执行的是一个Java方法,计数器记录的是正在执行的虚拟机字节码指令的地 址 2.如果正在执行的是 Native方法,这个计数器的值为空 程序计数器是唯一—个没有规定任何 OutofMemoryError的区域 Java虚拟机栈(线程私有) Java虚拟机栈( Java virtual machine stacks)是线程私有的,生命周期与线程相同。 虛拟机栈描述的是Ja阳a方法执行的内存模型:每个方法被执行的时候都会创建一个栈 帧( Stack frame),存储 1.局部变量表 2.操作栈 3.动态链接 4.方法出口 每—一个方法被调用到执行完成的过程,就对应着一个栈帧在虛拟机栈从入栈到出栈的过程。 这个区域有两种异常情况: 1. StackOverflow error:线程请求的栈深度大于虚拟机所允许的深度 2. OutOfMemoryError:虚拟机栈扩展到无法申请足够的内存时 本地方法栈(线程私有 虚拟机栈为虚拟机执行Java方法(字节码)服务。 本地方法栈( Native method stacks)为虚拟机使用到的 Native方法服务。 Java堆(线程共享) Java堆( Java Heap)是Java虚拟机内存最大的一块。Java堆在虚拟机启动时创建,被所 有线程共享。 作用:存放对象实例。垃圾收集器主要管理的就是Java堆。Java堆在物理上可以不连续,只 要逻辑上连续即可。 方法区(线程共亨) 方法区( Method area)被所有线程共享,用于存储已被虛拟机加载的类信息、常量、静态 变量、即时编译器编译后的代码等数据。 和Java堆一样,不需要连续的内存,可以选择固定的大小,更可以选择不实现垃圾收集。 运行时常量池 运行时常量池( Runtime Constant pool)是方法区的一部分。保存 Class文件的符号引 用、翻译岀来的直接引用。运行时常量池可以在运行期间将新的常量放入池 Java对象访问是如何进行的? Object ob j new Object( 对于上述最简单的访问,也会涉及到Java栈、Java堆、方法区这三个最重要内存区域。 Object obj 如果出现在方法体,则上述代码会反映到Java栈的本地变量表,作为 reference类型数 据出现。 new Object( 反映到Java,形成一块存储了 bject类型所有对象实例数据值的内存。Java还包 含对象类型数据的地址信息,这些类型数据存储在方法区, 如何判断对象是否“死去”? 1.引用计数法 2.根搜索算法 什么是引用计数法? 给对象添加一个引用计数器,每当有一个地方引用它,计数器就+1,;当引用失效时,计数器 就-1;任何时刻计数器都为0的对象就是不能再被使用的 引用计数法的缺点? 很难解决对象之间的循环引用问题。 什么是根搜索算法? 通过一系列的名为" GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过 的路径称为引用链( Reference chain),当一个对象到 GC Roots没有任何引用链相连(用 图论的话来说就是从 GC Roots到这个对象不可达)时,则证明此对象是不可用的。 object 5 object 6 object 7 仍然存活的对象 □判定可回收的对象 Java的4种引用方式? 在」DK1.2之后,Java对引用的概念进行了扩充,将引用分为 1.强引用 Strong reference 2.软引用 Soft reference 3.弱引用 Weak Reference 4.虚引用 Phantom reference 强引用

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值