jdk9+版本的bug

简介: 今天从jvm大神"你假笨"的公众号上,看到一个jdk 9+版本的编译bug,记录一下: public class JavacEvalBug{ private static String[] array = {""}; static int test(){ System.

今天从jvm大神"你假笨"的公众号上,看到一个jdk 9+版本的编译bug,记录一下:

public class JavacEvalBug{

    private static String[] array = {""};

    static int test(){
        System.out.println("evaluated!");
        return 0;
    }

    public static void main(String[] args) {
        //相当于int index=test(); array[index] +="a";
        array[test()] += "a";
    }

}

test()方法里输出了一个固定字符串,上面这段代码,如果是在jdk8版本里,执行后,只会输出:evaluated! 一次(这符合预期,因为test()只调用了1次)

但如果把jdk升级到jdk9或10,再次编译运行,evaluated!就会输出2次,即test()方法会多执行了1次,如果test()方法是复杂的业务逻辑,比如创建订单/库存扣减之类,这就成大问题了。

原因在于jdk8与jdk9+的编译机制不同,javap -verbose JavacEvalBug  使用这个命令,可以看到编译细节:

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=5, locals=1, args_size=1
         0: new           #5                  // class java/lang/StringBuilder
         3: dup
         4: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
         7: getstatic     #7                  // Field array:[Ljava/lang/String;
        10: invokestatic  #8                  // Method test:()I
        13: dup2_x1
        14: aaload
        15: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        18: iconst_1
        19: invokevirtual #10                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
        22: invokevirtual #11                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        25: aastore
        26: return

jdk8上,从第10行看,只调用了1次,如果切换到jdk9+,则会变成:

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=1, args_size=1
         0: getstatic     #5                  // Field array:[Ljava/lang/String;
         3: invokestatic  #6                  // Method test:()I
         6: getstatic     #5                  // Field array:[Ljava/lang/String;
         9: invokestatic  #6                  // Method test:()I
        12: aaload
        13: invokedynamic #7,  0              // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
        18: aastore
        19: return
      LineNumberTable:

明显可以看到Method test:()I 调用了2次。具体详情分析,大神说是以后会详细分析,大概是字符串拼写的方式,jdk9以后做了变化。如果把string数组换成其它类型比如int

public class JavacEvalBug{
    private static int[] array = {0};

    static int test(){
        System.out.println("evaluated!");
        return 0;
    }

    public static void main(String[] args) {
        //相当于int index=test(); array[index] +=1;
        array[test()] += 1;
    }
}

就正常了

 

2018-07-28 更新,在jdk 10.0.2版本上,该bug已修复

作者: 菩提树下的杨过
出处: http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
目录
相关文章
|
2月前
|
JSON 编解码 Java
Java升级:JDK 9新特性全面解析“
Java升级:JDK 9新特性全面解析“
28 0
|
3月前
|
Java Linux 开发工具
Jenv 多版本JDK管理
Jenv 可以对多版本JDK进行管理
|
3月前
|
Oracle JavaScript Java
JDK的版本迭代特性(JDK9 - JDK20)
JDK的版本迭代特性(JDK9 - JDK20)
|
2月前
|
Oracle Java 编译器
基本概念【入门、 发展简史、核心优势、各版本的含义、特性和优势、JVM、JRE 和 JDK 】(二)-全面详解(学习总结---从入门到深化)
基本概念【入门、 发展简史、核心优势、各版本的含义、特性和优势、JVM、JRE 和 JDK 】(二)-全面详解(学习总结---从入门到深化)
46 1
|
22天前
|
Java 应用服务中间件 nginx
idea打war包时,JDK版本的问题解决方式
idea打war包时,JDK版本的问题解决方式
13 0
|
23天前
|
Java API 计算机视觉
java实现人脸识别V3版本开发
java实现人脸识别V3版本开发
17 0
|
1月前
|
Java
916.【Java】javap 查看 class 文件的jdk编译版本
916.【Java】javap 查看 class 文件的jdk编译版本
32 2
|
1月前
|
Oracle 安全 Java
JDK收费的各个版本(记录一下)
JDK收费的各个版本(记录一下)
183 0
|
2月前
|
Oracle Java 关系型数据库
JDK各版本的官方下载地址
JDK各版本的官方下载地址
|
2月前
|
算法 Java
蓝桥杯算法题——题解Java版本——切面条
蓝桥杯算法题——题解Java版本——切面条
34 0