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)
有人对此有任何想法吗?
程序运行环境规范是这样的:
服务器:
发展:
IDE:版本:2019-09 R (4.13.0)
JDK:jdk-11.0.1
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)
但是,默认情况下,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)
| 归档时间: |
|
| 查看次数: |
14735 次 |
| 最近记录: |