以往如果需要调用C/C++代码去实现一些底层的操作,需要使用JNI(Java Native Interface)。就以cls清屏功能为例,需要自己编写相应的C/C++并生成dll文件,然后再通过JNI的方式调用dll来实现相应的功能,具体步骤可以参考这篇博客:使用JNA在Java中实现cls(命令行清屏)功能,这里展示了如何使用基于JNI的JNA框架来调用dll文件去实现cls清屏功能。而在Java 17中,我们便不再需要编写C/C++代码以及生成dll文件,而仅仅只需要写Java代码即可(目前还处于孵化器阶段),下面展示具体的使用方法。
实现在介绍之前,先展示最终的代码:
import jdk.incubator.foreign.Clinker;
import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.ResourceScope;
import java.lang.invoke.MethodType;
import static jdk.incubator.foreign.Clinker.C_POINTER;
public class Main {
public static void main(String[] args) throws Throwable {
// 简单跑马灯对照效果
var tip = "等待清屏...";
var begin = 0;
var end = 10;
var interval = 1000;
var backspaces = "b".repeat(tip.length());
while (begin++ < end) {
tip = tip.substring(1) + tip.charAt(0);
System.out.print(backspaces + tip);
Thread.sleep(interval);
cls();
}
System.out.print("清屏成功");
}
private static void cls() throws Throwable {
// 获取 system 函数
var systemFunction = Clinker.systemLookup().lookup("system").orElseThrow();
// 标识 system 函数的返回值及参数类型
var systemHandle = Clinker.getInstance().downcallHandle(
systemFunction,
MethodType.methodType(void.class, MemoryAddress.class),
FunctionDescriptor.ofVoid(C_POINTER)
);
// 获取存储在本地内存段中的 "cls" 字符串, 用于执行 system("cls") 清屏函数
var clsStr = Clinker.toCString("cls", ResourceScope.newImplicitScope());
// 执行 system("cls") 清屏函数
systemHandle.invoke(clsStr.address());
}
}
可以发现我们现在可以直接在Java中调用C/C++中的system函数并执行cls清屏命令,编写的代码也不算太多,这里结合注释也能够基本理解。
效果下面再展示上述代码的实际效果:
配置由于该功能仍然处于孵化器阶段,所以想要体验的话,还需要进行一些配置,下面已IDEA的配置为例进行讲解:
首先选择File -> Settings,然后找到一下配置界面:
其中Compilation options中的配置内容如下:
--add-modules jdk.incubator.foreign --add-exports java.base/jdk.internal.access=ALL-UNNAMED
然后加入如下的VM options参数:
--add-modules jdk.incubator.foreign --enable-native-access ALL-UNNAMED
完成以上配置,即可以体验cls清屏功能了,不过使用IDEA的run窗口运行会出现乱码,所以需要选择Terminal窗口,或者使用cmd命令窗口,在项目的根目录下输入以下命令即可(outproductionjni中的jni需要替换为自己的项目名):
java --add-modules jdk.incubator.foreign --enable-native-access ALL-UNNAMED -classpath outproductionjni Mainjna 方式实现
下面再简单介绍如果使用基于jni的jna实现cls的清屏功能,详细步骤可以参考使用JNA在Java中实现cls(命令行清屏)功能,这里不再展示dll文件(点击这里下载)的生成步骤:
pom的配置如下:
8 8 5.10.0 net.java.dev.jna jna ${jna.version} net.java.dev.jna jna-platform ${jna.version}
代码结构如下:
└─src
└─main
├─java
├──── Cls.java
├──── Main.java
│
└─resources
├──── clsscreen.dll
其中clsscreen.dll即为上文提到要下载的文件。
Cls.java内容如下:
import com.sun.jna.Library;
import com.sun.jna.Native;
import java.util.Objects;
public interface Cls extends Library {
String DLL_FILE_NAME = "clsscreen.dll";
Cls DLL = Native.load(
Objects.requireNonNull(Cls.class.getResource(DLL_FILE_NAME)).getPath().substring(1), Cls.class);
void cls();
}
Main.java的内容如下:
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) throws InterruptedException {
// 简单跑马灯对照效果
String tip = "等待清屏...";
int begin = 0;
int end = 10;
int interval = 1000;
String backspaces = Stream.generate(() -> "b")
.limit(tip.length())
.collect(Collectors.joining());
while (begin++ < end) {
tip = tip.substring(1) + tip.charAt(0);
System.out.print(backspaces + tip);
Thread.sleep(interval);
Cls.DLL.cls();
}
System.out.print("清屏成功");
}
}
效果如下:



