跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 踩了一个 Java 编译时和运行时环境不一致导致的一个坑
未分類
22 10 月 2020

踩了一个 Java 编译时和运行时环境不一致导致的一个坑

踩了一个 Java 编译时和运行时环境不一致导致的一个坑

資深大佬 : pursuer 2

这两天测试了一段代码,在 Java11 上正常运行,在 android 上运行报 NoSuchMethodError 异常,异常处就一句

//buf 是一个 ByteBuffer
buf.flip()

报的异常是
java.lang.NoSuchMethodError: No virtual method flip()Ljava.nio.ByteBuffer in class java.nio.ByteBuffer (我凭记忆还原的,可能不完全一样)

通常出现这样的问题的时候我第一反应是使用了 android 不支持的高版本 API 导致的。但翻了下 Java 的 API 文档,发现 flip 函数在有 ByteBuffer 的时候就存在了,然后再看方法签名,注意到报异常的函数签名是 flip()Ljava.nio.ByteBuffer,但查阅的文档中这个函数的签名应该是 flip():Ljava.nio.Buffer,猜测是不是编译的时候选择调用了另一个高版本中存在的方法签名,但是不知道怎么处理。
后来在 StackOverflow 上找到了这个问题的解答。在 Java9 的时候 ByteBuffer 覆写了父类 Buffer 的 flip,mark,reset 等函数,并将返回值改为了 ByteBuffer,导致高版本编译的时候,javac 选择调用了 flip()Ljava.nio.ByteBuffer,在低版本的运行环境中没有这个方法签名,导致出错。解决方法是((Buffer)buf).flip()
感觉 Java 在这块的设计有些奇特,Java 没有返回值重载,但 JVM 实现上却会将不同返回值认定为不同的方法。

大佬有話說 (6)

  • 主 資深大佬 : pursuer

    更正一下,我再次检查文档的时候发现 Java8 的时候 flip 方法是 final 的,但 Java11 后去掉了,导致编译器在高版本下使用了 invokevirtual 指令调用 flip 函数,导致低版本产生异常。上面提到的“JVM 将不同返回值认定为不同方法“这一说法是不成立的。

  • 主 資深大佬 : pursuer

    再次更正,我查到 final 关键字对字节码生成没有影响,所以上面说的指令差异也是不对的,那可能还是因为方法签名的问题吧。

  • 資深大佬 : SoloCompany

    java 兼容性如果都能挑剔的话别的就更不要说了

    你说的的这种问题是常见情形, 如果你一定需要使用高版本的 javac 的话, 正确的做法是给 javac 指定 bootstrapclasspath, 使用 JAVA 8 的 rt.jar, 仅仅靠 -source / -target 参数是无法保证 bytecode 能在低版本的 runtime 下运行

  • 資深大佬 : abcbuzhiming

    java 好像从来没保证说高版本编译的 class 可以在低版本 jvm 上跑啊,我记得 jvm 一直说的是向上兼容,即低版本 jdk 编译的 class 可以跑在高版本 jvm 上(但是从 java9 开始这也不完全保证了,好像只保证 3 个版本之类是兼容的);向下兼容没听说过

  • 主 資深大佬 : pursuer

    @SoloCompany
    @abcbuzhiming
    无奈 Android 的运行时碎片化太厉害,还是会需要使用高版本 android.jar 编译同时要应用兼容低版本系统。

  • 資深大佬 : Goooogle

    Java 在编译时,会将使用到的方法的签名固化在字节码中的常量池中(类型为 CONSTANT_Methodref_info ),当运行时和编译时的签名不一样时,就会报这个错误。即使是“将参数类型改为其父类型”这种直观看起来可行的方式也不行。
    你例子中,ByteBuffer 是 Buffer 的子类型,单纯从语法上讲,把一个方法的 ByteBuffer 参数的类型替换成 Buffer,所有这个方法的调用方都能继续调用,不会有任何问题,但在编译后的方法执行时先去常量池找到对应的符号引用,但该符号引用在运行时环境中没有,不会判断继承关系,而是直接抛出异常。

    前段时间刚碰到这个问题。

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具