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
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
目录
相关文章
|
12天前
|
安全 架构师 Java
Java LTS版本进化秀:从8到21的欢乐升级之旅
困惑于Java版本选择?轻松幽默地穿越Java LTS版本时光隧道,掌握从Java 8到21的关键特性。通过一家初创公司的系统升级故事,直观了解每个版本如何解决代码冗余、性能瓶颈等开发痛点,助你在技术选型中做出明智决策。
|
5月前
|
Java
IDEA修改JDK版本
在IDEA中修改项目JDK版本的方法如下:1. 右键点击项目;2. 选择“Open Module Settings”,如图所示;3. 在弹出窗口中配置自定义的JDK路径。通过以上步骤,可轻松更改项目所使用的JDK版本,满足不同开发环境的需求。
1106 65
|
2月前
|
Cloud Native Java API
Java Spring框架技术栈选和最新版本及发展史详解(截至2025年8月)-优雅草卓伊凡
Java Spring框架技术栈选和最新版本及发展史详解(截至2025年8月)-优雅草卓伊凡
296 0
|
3月前
|
安全 Java API
Java 17 及以上版本核心特性在现代开发实践中的深度应用与高效实践方法 Java 开发实践
本项目以“学生成绩管理系统”为例,深入实践Java 17+核心特性与现代开发技术。采用Spring Boot 3.1、WebFlux、R2DBC等构建响应式应用,结合Record类、模式匹配、Stream优化等新特性提升代码质量。涵盖容器化部署(Docker)、自动化测试、性能优化及安全加固,全面展示Java最新技术在实际项目中的应用,助力开发者掌握现代化Java开发方法。
130 1
|
2月前
|
Ubuntu Java Android开发
在Ubuntu 18.04上安装与JDK 8兼容的Eclipse版本的步骤。
安装过程结束后,您就可以开始使用Eclipse来开发您的Java项目了,并且确保它与JDK 8兼容无误。这个过程涉及的是一个基本的安装流程,针对使用Java 8的用户,Eclipse的其他配置和插件安装根据个人开发环境和需求来定制。
164 0
|
8月前
|
JavaScript NoSQL Java
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
383 96
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
|
5月前
|
JavaScript Java 关系型数据库
家政系统源码,java版本
这是一款基于SpringBoot后端框架、MySQL数据库及Uniapp移动端开发的家政预约上门服务系统。
160 6
家政系统源码,java版本
|
6月前
|
Java API 开发工具
Android cmdline-tools版本与最小JDK的关系
总的来说,Android的命令行工具和JDK之间的关系就像是一场舞会,两者需要彼此配合,才能共同创造出美妙的舞蹈。如果选择了不合适的舞伴(即不兼容的版本),可能会导致舞蹈中的步伐混乱,甚至无法完成舞蹈。而即使选择了合适的舞伴,也需要考虑舞伴的舞蹈技巧(即性能和稳定性),才能确保舞蹈的完美表现。因此,选择合适的Android命令行工具和JDK版本,是每一个Android开发者都需要面对的重要决定。
198 13
|
10月前
|
安全 Java 编译器
一个 Bug JDK 居然改了十年?
你敢相信么一个简单的Bug,JDK 居然花了十年时间才修改完成。赶快来看看到底是个什么样的 Bug?
110 1
一个 Bug JDK 居然改了十年?
|
11月前
|
Java Linux Windows
如何查看已安装的 Java 版本
要查看已安装的 Java 版本,打开命令提示符或终端,输入 `java -version`,回车后即可显示当前系统中 Java 的版本信息。
3683 1

热门文章

最新文章