JNI 和构造函数

2024-02-08

我有一个已编译的库,需要在项目中使用。简而言之,它是一个用于与特定硬件交互的库。我拥有的是 .a 和 .dll 库文件,分别适用于 Linux 和 Windows,以及一堆 C++ .h 头文件,其中包含其中描述的所有公共函数和类。

问题是该项目需要使用 Java,因此我需要为这个库编写一个 JNI 包装器,老实说,我从未这样做过。不过没关系,我正准备学习这个东西。

我在线阅读了一堆文档,并且弄清楚了传递变量、从本机代码创建 java 对象等。

我不明白的是如何使用 JNI 来处理本机构造函数?我不知道这些构造函数的源代码是什么,我只有这样的标题:

namespace RFDevice {

class RFDEVICE_API RFEthernetDetector
{
public:
    //-----------------------------------------------------------------------------
    //  FUNCTION  RFEthernetDetector::RFEthernetDetector
    /// \brief    Default constructor of RFEthernetDetector object.
    ///           
    /// \return   void : N/A
    //-----------------------------------------------------------------------------
    RFEthernetDetector();
    RFEthernetDetector(const WORD wCustomPortNumber);

所以基本上如果我用 C++ 编写程序(我不能),我会做类似的事情

RFEthernetDetector ethernetDetector = new RFEthernerDetector(somePort);

然后处理该对象。但是...我如何使用 JNI 在 Java 中执行此操作? 我不明白我应该如何为构造函数创建一个本机方法,该方法将从我的 .a 库调用构造函数,然后以某种方式处理该特定对象?我知道如何从本机代码创建 java 对象 - 但问题是我没有任何有关 RFEthernetDetector 类的内部结构的信息 - 只有其中的一些公共字段和公共方法。

我似乎无法在网上找到合适的文章来帮助我。我怎么做?

更新:进一步澄清一下。

我创建一个 .java 包装类,如下所示:

public class RFEthernetDetector
{
    public RFEthernetDetector(int portNumber)
    {
        Init(portNumber);
    }

    public native void Init(int portNumber);            // Void? Or what?
}

然后我用 -h 参数编译它以生成 JNI .h 文件:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class RFEthernetDetector */

#ifndef _Included_RFEthernetDetector
#define _Included_RFEthernetDetector
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     RFEthernetDetector
 * Method:    Init
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_RFEthernetDetector_Init
  (JNIEnv *, jobject, jint);

#ifdef __cplusplus
}
#endif
#endif

然后,我创建一个实现,它将调用我的 .a 库中的函数:

#include "RFEthernetDetector.h"     // auto-generated JNI header
#include "RFEthernetDetector_native.h"  // h file that comes with the library, 
                    //contains definition of RFEthernetDetector class
/*
 * Class:     RFEthernetDetector
 * Method:    Init
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_RFEthernetDetector_Init(JNIEnv *env, jobject thisObj, jint value)
{
    RFEthernetDetector *rfeDetector = new RFEthernetDetector(value);    // constructor from the library
    // now how do I access this new object from Java?
    // if I need to later call rfDetector->doSomething() on that exact class instance?
}

你需要建立一个RFEthernetDetectorJava 类,通过指针,owns a RFEthernetDetector在C++方面。这一点都不好玩 https://stackoverflow.com/q/337268/5684257,但语言间的粘合从来都不是。

// In this design, the C++ object needs to be explicitly destroyed by calling
// close() on the Java side.
// I think that Eclipse, at least, is configured by default to complain
// if an AutoCloseable is never close()d.
public class RFEthernetDetector implements AutoCloseable {
   private final long cxxThis; // using the "store pointers as longs" convention
   private boolean closed = false;
   public RFEthernetDetector(int port) {
       cxxThis = cxxConstruct(port);
   };
   @Override
   public void close() {
       if(!closed) {
           cxxDestroy(cxxThis);
           closed = true;
       }
   }
   private static native long cxxConstruct(int port);
   private static native void cxxDestroy(long cxxThis);

   // Works fine as a safety net, I suppose...
   @Override
   @Deprecated
   protected void finalize() {
       close();
   }
}

在 C++ 方面:

#include "RFEthernetDetector.h"

JNIEXPORT jlong JNICALL Java_RFEthernetDetector_cxxConstruct(JNIEnv *, jclass, jint port) {
    return reinterpret_cast<jlong>(new RFEthernetDetector(port));
}

JNIEXPORT void JNICALL Java_RFEthernetDetector_cxxDestroy(JNIEnv *, jclass, jlong thiz) {
    delete reinterpret_cast<RFEthernetDetector*>(thiz);
    // calling other methods is similar:
    // pass the cxxThis to C++, cast it, and do something through it
}

如果这一切reinterpret_casting 让您感到不舒服,您可以选择保留map around:

#include <map>

std::map<jlong, RFEthernetDetector> references;

JNIEXPORT jlong JNICALL Java_RFEthernetDetector_cxxConstruct(JNIEnv *, jclass, jint port) {
    jlong next = 0;
    auto it = references.begin();
    for(; it != references.end() && it->first == next; it++) next++;
    references.emplace_hint(it, next, port);
    return next;
}

JNIEXPORT void JNICALL Java_RFEthernetDetector_cxxDestroy(JNIEnv *, jclass, jlong thiz) {
    references.erase(thiz);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JNI 和构造函数 的相关文章

随机推荐

  • 按字节截断字符串

    我创建以下内容 用于将 java 中的字符串截断为具有给定字节数的新字符串 String truncatedValue String currentValue string int pivotIndex int Math round dou
  • 我如何用更少的node_modules创建react-app

    我用过create react app
  • RegExp 和 String 组合导致 Chrome 崩溃

    我有以下正则表达式来验证电子邮件地址 A Za z0 9 a zA Z0 9 A Za z0 9 a zA Z0 9 A Za z 2 在基本电子邮件上运行它效果很好 A Za z0 9 a zA Z0 9 A Za z0 9 a zA Z
  • 使用 *args 和 **kwargs [重复]

    这个问题在这里已经有答案了 所以我对这个概念有困难 args and kwargs 到目前为止我了解到 args 参数列表 作为位置参数 kwargs 字典 其键成为单独的关键字参数 值成为这些参数的值 我不明白这对什么编程任务有帮助 Ma
  • 如何同时使用 telegram bot python

    我不知道如何使用 python 在电报中使用机器人进行多进程 我创建了一个线程 但如果该线程未完成 机器人将无法回复消息 horaPurga now replace hour 23 minute 36 second 59 microseco
  • RESTEasy - javax.ws.rs.NotFoundException:找不到完整路径的资源

    我尝试在 GWT 项目中使用 RESTEasy 实现 REST 服务 但是当我进入相应的 URI 时 应用程序返回 Grave failed to execute javax ws rs NotFoundException Could no
  • 不活动后会话自动注销

    快速会话中是否有内置功能 可以在给定的不活动时间后启用自动注销 我如下使用它 并希望它在会话半小时不活动时注销 app use session key sessid secret This is secret resave true sav
  • C#“使用”块

    我有类似下面的代码 这里有人提到 WebClient Stream 和 StreamReader 对象都可以从使用块中受益 两个简单的问题 1 这个小片段在使用块时会是什么样子 我自己做研究没有问题 所以资源链接很好 但只看一个例子会更快更
  • 与具有私有成员函数的类相比,未命名命名空间中的自由函数有什么好处?

    与拥有不带任何参数的私有类成员函数并直接访问成员变量相比 拥有自由函数 在匿名命名空间中并且只能在单个源文件中访问 并将所有变量作为参数发送有什么优势 header class A int myVariable void DoSomethi
  • C# 中的赋值运算符

    据我了解 与 C 不同 在 C 中不可能重写赋值运算符 如果我们想要将类 C 的实例 i1 分配给另一个实例 i2 C 类 则有必要创建一个复制方法 但困境来了 我有一个通用的 T 类 public class Node
  • 如何选择 div 内的图像来更改其来源?

    我有以下 div 并且我知道该 DIV 的选择器 Id div class event img src Content Images Icons calendar16 png Event Name div 但我不知道 图像是什么 我需要一些
  • 是否有可能在 Swift 中创建一个仅限于一个类的数组扩展?

    我可以制作一个仅适用于字符串等的数组扩展吗 从 Swift 2 开始 现在可以通过以下方式实现协议扩展 为符合类型提供方法和属性实现 可选地受到附加约束的限制 一个简单的例子 为所有符合的类型定义一个方法 到SequenceType 例如A
  • Hive 中的 ParseException

    我正在尝试使用UDF在蜂巢中 但是当我尝试使用创建临时函数时userdate as unixtimeToDate 我得到这个异常 hive gt create temporary function userdate1 as unixtime
  • Mod_rewrite:在特定页面上强制使用 SSL。在非安全页面上添加 www

    我知道这是一个常见的话题 但我已尽最大努力借助在网上搜索到的解决方案来解决它 我们有一个链接到子域 secure mysite com 的证书 我们希望实现以下目标 我们需要在以下路径及其子页面上强制使用 SSL http mysite c
  • .NET 字符串操作区分大小写吗?

    NET 字符串函数是这样的吗IndexOf blah 区分大小写 据我所知 它们不是 但出于某种原因 我在我的应用程序中看到了错误 其中查询字符串中的文本采用驼峰式大小写 如 UserID 并且我正在测试IndexOf userid 是的
  • JavaScript 中的 Char 数组到 Int32

    我有一个 char 数组 data 和一个 Int32 dictIdFrame 我希望 dictIdFrame 采用 data i i 3 的 ASCII 0 255 值 我的意思是四个字节变成一个 int32 其中 data i 是不太重
  • android.util.Log 中的错误或功能? - Log.isLoggable(DEBUG) = false 但 Log.d() 未禁用

    更新 重新制定问题和标题 我一直认为昂贵的 android 日志记录方法可以通过询问日志记录是否像这样活跃来优化 import android util Log if Log isLoggable MyContext Log DEBUG L
  • 用于将条件数据复制到特定单元格的 VBA 宏

    我是 VBA 编程新手 我正在寻找从匹配条件的不同工作表中获取数据 然后从一个特定单元格复制并粘贴到另一个特定单元格 7 次 我的代码不起作用 我正在寻求改进它 当我运行代码时 我在 IF 语句开头被标记为运行时错误 1004 方法 对象范
  • Twitter 的 Bootstrap Datepicker 缺少 Glyphicons

    我正在尝试使用引导程序中的日期选择器 http eternicode github io bootstrap datepicker http eternicode github io bootstrap datepicker 并且一切正常
  • JNI 和构造函数

    我有一个已编译的库 需要在项目中使用 简而言之 它是一个用于与特定硬件交互的库 我拥有的是 a 和 dll 库文件 分别适用于 Linux 和 Windows 以及一堆 C h 头文件 其中包含其中描述的所有公共函数和类 问题是该项目需要使