线程“main”中的异常 java.lang.NoSuchMethodError: java.nio.ByteBuffer.flip()Ljava/nio/ByteBuffer

gar*_*ong 29 java bytebuffer java-8 java-11

我有一个方法如下,它已经正常运行了很长时间:

private String loadFromFile(){

    RandomAccessFile inFile = null;
    FileChannel inChannel = null;
    StringBuilder sb = new StringBuilder();
    try {

        inFile = new RandomAccessFile(this.latestImageFile, "r");
        inChannel = inFile.getChannel();

        ByteBuffer bb = ByteBuffer.allocate(2046);
        while( inChannel.read(bb) != -1){
            bb.flip();

            while(bb.hasRemaining()){
                char c = (char) bb.get();   // read character at current position and set the pointer to current position + 1
                sb.append(c);
            }

            bb.clear();
        }

    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (inChannel != null) try {inChannel.close(); } catch (IOException e){}
        if (inFile != null ) try { inFile.close(); } catch (IOException e) {}
    }

    return sb.toString();
}
Run Code Online (Sandbox Code Playgroud)

但是,今天在服务器上编译并运行程序后,启动程序时记录了以下异常。它显示未找到 flip() 方法:

Exception in thread "main" java.lang.NoSuchMethodError: java.nio.ByteBuffer.flip()Ljava/nio/ByteBuffer;
        at com.rt.stream.s.exch.OBWorker.loadFromFile(OBWorker.java:271)
        at com.rt.stream.s.exch.OBWorker.initAndLoadOBs(OBWorker.java:184)
        at com.rt.stream.s.exch.OBWorker.<init>(OBWorker.java:145)
        at com.rt.stream.s.exch.OBWorkerMgr.initFromProperties(OBWorkerMgr.java:217)
        at com.rt.stream.s.exch.OBWorkerMgr.init(OBWorkerMgr.java:132)
        at com.rt.stream.s.exch.OBWorkerMgr.main(OBWorkerMgr.java:511)
Run Code Online (Sandbox Code Playgroud)

有人对此有任何想法吗?

程序运行环境规范是这样的:

服务器:

  1. openjdk 版本“1.8.0_242”

发展:

  1. IDE:版本:2019-09 R (4.13.0)

  2. JDK:jdk-11.0.1

  3. maven:apache-maven-3.3.3(应用以下配置)

   <source>1.8</source>   
   <target>1.8</target>
Run Code Online (Sandbox Code Playgroud)

gar*_*ong 36

在搜索了一段时间并通过在 8 和 11 之间切换已安装的 JDK 进行验证后,我发现有一些更改(new overridden methods)应用于ByteBuffer 类中的几个方法(例如flip()、clear())。

在Java 8中,调用flip()ByteBuffer类的方法时,由于没有实现该方法,所以实际上是从扩展类Buffer调用该方法;这是返回Buffer对象如下:

缓冲区类中:

public final Buffer flip() {
    limit = position;
    position = 0;
    mark = -1;
    return this;
}
Run Code Online (Sandbox Code Playgroud)

但是在Java 11中,ByteBuffer类已经实现了自己的flip()方法,并且返回的对象从Buffer变成了ByteBuffer(这个变化应该是从Java 9开始的):

ByteBuffer类中:

ByteBuffer flip() {
    super.flip();
    return this;
}
Run Code Online (Sandbox Code Playgroud)
由于我使用 JDK 11(更高的 JDK 版本)来编译程序以在 Java 8 上运行,因此偶尔会遇到相应于 javadoc 的异常:

但是,默认情况下,javac 会针对平台 API 的最新版本进行编译。因此,编译后的程序可能会意外使用仅在当前平台版本中可用的 API。无论传递给 -source 和 -target 选项的值如何,此类程序都无法在旧版本的平台上运行。这是一个长期可用性痛点,因为用户希望通过使用这些选项,他们将获得可以在 -target 指定的平台版本上运行的类文件。

该声明可以在这里引用:http : //openjdk.java.net/jeps/247



因此,要解决此类问题,有两种方法:


方法一

通过使用新引入的命令行选项,可以在编译期间进行处理:

i.e.
javac --release N <source files>

which is equals to:
for N < 9: -source N -target N -bootclasspath <documented-APIs-from-N>,  
for N >= 9: -source N -target N --system <documented-APIs-from-N>.  
Run Code Online (Sandbox Code Playgroud)

方法二

或者我们可以在代码中处理它,作为预防方法,通过在调用相应方法之前将 ByteByffer 显式转换为 Buffer:

((缓冲区) bb).翻转();

为了强制它调用扩展类的方法(以防编译过程没有考虑新的命令行选项):

private String loadFromFile(){
    
    RandomAccessFile inFile = null;
    FileChannel inChannel = null;
    StringBuilder sb = new StringBuilder();
    try {

        inFile = new RandomAccessFile(this.latestImageFile, "r");
        inChannel = inFile.getChannel();
        
        ByteBuffer bb = ByteBuffer.allocate(2046);
        while( inChannel.read(bb) != -1){
            ((Buffer)bb).flip(); // explicitly casting
            
            while(bb.hasRemaining()){
                char c = (char) bb.get();
                sb.append(c);
            }
            
            ((Buffer) bb).clear(); // explicitly casting
        }
        
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (inChannel != null) try {inChannel.close(); } catch (IOException e){}
        if (inFile != null ) try { inFile.close(); } catch (IOException e) {}
    }
    
    return sb.toString();
}
Run Code Online (Sandbox Code Playgroud)

  • **方法 3** 只是使用用于执行的相同 jdk 进行开发 (4认同)
  • 这就是“--release”选项的用途。无需自己指定这三个不同的选项。这就是您链接的页面所描述的内容。 (3认同)