快速发布收录 推广展示
早上好, 游客 <游客> [ 马上登录 | 注册帐号 ]
首页 搜索优化 正文

Java修炼终极指南:158 引入外部链接器API

发布时间:2024-09-10 更新日期:2024-09-16 作者: 16757网址导航 阅读:46 次

Foreign Linker API的主要目标是提供一个健壮且易于使用的API(无需编写C/C++代码),以支持Java代码与C/C++本地共享库中的外部函数之间的互操作性(将来,其他编程语言也将通过此API获得支持)。 调用外部代码的旅程始于java.lang.foreign.SymbolLookup功能接口。该接口代表入口点,它由查找加载的本地共享库中给定符号的地址组成。有三种方法可以做到这一点,如下所示:Linker.defaultLookup() – 如其名称所示,defaultLookup()代表默认查找,它扫描并定位当前操作系统所使用所有常用本地共享库的所有符号。Linker linker = Linker.nativeLinker(); SymbolLookup lookup = linker.defaultLookup();SymbolLookup.loaderLookup() – 代表加载器查找,它扫描并定位当前类加载器加载的所有本地共享库中的所有符号(通过System.loadLibrary()和System.load()基于java.library.path)。System.loadLibrary("fooLib"); // 这里加载fooLib.dll SymbolLookup lookup = SymbolLookup.loaderLookup();SymbolLookup.libraryLookup(String name, Arena arena) – 代表库查找,能够扫描并加载arena范围内的给定名称的本地共享库,并为该本地共享库中的所有符号创建符号查找。或者,我们可以通过SymbolLookup.libraryLookup(Path path, Arena arena)指定路径。try (Arena arena = Arena.openConfined()) { SymbolLookup lookup = SymbolLookup.libraryLookup( libName/libPath, arena.scope()); }如果成功完成这一步,那么我们可以选择与我们要调用的外部函数相对应的符号。通过SymbolLookup.find(String name)方法可以按名称找到外部函数。如果指向的方法存在于定位的符号中,则find()返回一个包装在Optional中的零长度内存段(Optional<MemorySegment>)。这个段的基地址指向外部函数的入口点。MemorySegment fooFunc = mathLookup.find("fooFunc").get();到目前为止,我们已经定位了本地共享库并找到了它的一个方法(fooFunc)。接下来,我们必须将Java代码链接到这个外部函数。这是通过基于两个概念的Linker API实现的:下调用(downcall) - 从Java代码调用本地代码上调用(upcall) - 从本地代码调用Java代码 这两个概念由Linker接口具体化。下调用映射在两个方法中,具有以下签名:MethodHandle downcallHandle(FunctionDescriptor function, Linker.Option... options)default MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function, Linker.Option... options) 通常,使用通过find()方法获得的默认方法,一个描述外部函数签名的函数描述符,以及一组可选的链接器选项。返回的MethodHandle稍后用于通过invoke(),invokeExact()等调用外部函数。通过invoke()或invokeExact()我们向外部函数传递参数并访问运行外部函数返回的结果(如果有的话)。 上调用由以下方法映射:MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, SegmentScope scope) 通常,target参数引用Java方法,function参数描述Java方法签名,scope参数表示与返回的MemorySegment相关联的范围。这个MemorySegment稍后作为调用(invoke()/invokeExact())下调用方法句柄的Java代码的参数传递。因此,这个MemorySegment充当函数指针。 如果我们将这些知识结合起来,那么我们可以编写一个经典的调用getpid()方法的示例,如下所示(考虑阅读有意义的评论以了解每个步骤的见解):// 获取底层本地平台的Linker
// (运行JVM的操作系统+处理器)
Linker linker = Linker.nativeLinker();
       
// "_getpid"是通用C运行时(UCRT)库的一部分
SymbolLookup libLookup = linker.defaultLookup();
       
// 查找"_getpid"外部函数
MemorySegment segmentGetpid = libLookup.find("_getpid").get();
// 为"_getpid"创建方法句柄
MethodHandle func = linker.downcallHandle(segmentGetpid,
  FunctionDescriptor.of(ValueLayout.JAVA_INT));
// 调用外部函数"_getpid"并获取结果
int result = (int) func.invokeExact();      
System.out.println(result);此代码已在Windows 10上测试。如果您运行不同的操作系统,则考虑了解此外部函数以相应地调整代码。

共收录0个网站,0个公众号,0个小程序,0个资讯文章,0个微信文章
首页 关于我们 联系我们 广告合作 免责声明 友情链接 TAGS标签
点击收藏小提示:按键盘CTRL+D也能收藏哦!
网站声明:本站所有资料取之于互联网,任何公司或个人参考使用本资料请自辨真伪、后果自负,不承担任何责任。在此特别感谢您对分类目录网的支持与厚爱!
16757分类目录版权所有©(2006-2025)16757.COM All Rights Reserved.   黔ICP备19007148号-10