编译期语法糖(二)
foreach循环
在JDK5以后,开始引入的一种新的语法糖.支持数组和集合的遍历.
我们先来看数组:
1 | public class Demo05_1 { |
我们先通过javap命令反编译:
1 | public static void main(java.lang.String[]); |
在指令的前 24条,就是新建数组队列的语法糖
转换成对应的代码如下:
1 | int[] arr = new int[5]; |
然后我们再来分析后面的字节码,可以转换成对应的代码如下:
1 | int length = arr.length; |
可以看出,foreach 也是编译成fori进行遍历
集合进行foreach.
1 | public class Demo05_2 { |
使用javap进行反编译
1 | public static void main(java.lang.String[]); |
44: invokeinterface #5, 1 // InterfaceMethod java/util/List.iterator
可以看出这里调用了list.iterator 方法
51: invokeinterface #6, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
56: ifeq 79
这里调用了iterator.hasNext()方法,且如果为false跳转到79行
60: invokeinterface #7, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
65: checkcast #2 // class java/lang/Integer
这里通过iterator.next()获取元素,且获取的元素类型为Object ,需要调用checkcat进行类型转换.
所以,集合类的foreach方法语法糖可以翻译成如下代码:
1 | while(iterator.hasNext()){ |
switch语法糖
switch-String
1 | public class Demo05_3 { |
然后我们根据javap反编译
我们直接翻译字节码,翻译后的代码如下:
1 | public static void choose(String str){ |
可以,看出jvm将一个switch 拆分成两个switch来实现,然后再编译期,已经可以知道字符串的hashCode.
但是因为可能出现两个字符串hashCode相同,但是不是同一个字符串的情况,所以再case中进行二次确认.
为什么要在第一遍时比较hashCode,又要利用equals进行比较呢?
这是因为利用hashCode可以提高比较效率,减少可能的比较;而equals比较是为了防止hashCode冲突.
switch-enum
1 | public class Demo05_4 { |
反编译后
1 |
|
1 | 0: getstatic #2 // Field demo05/Demo05_4$1.$SwitchMap$demo05$Sex:[I |
这里可以看出,jvm帮我们生成了一个名叫Demo05_4$1的内部类
其中有一个int类型的数组
转换后这个内部类的代码如下:
1 | static class Demo05_4$1{ |
然后 利用一个byte类型的swatch进行操作.
枚举类
1 |
|
由于字节码比较多,我们直接看转换后代码.代码如下:
1 | public final class Sex extends Enum<Sex>{ |
这就是枚举类的jvm实现.