2023-01-20 295
我有一个我需要在项目中使用的编译库.简而言之,它是一个与特定硬件进行交互的库.我所拥有的是.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
i然后创建一个实现,该实现将从我的.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?
}
您需要构建RFEthernetDetector Java类,该类别通过指针, a RFEthernetDetector在C ++方面. 这不是一个有趣的
// 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_cast使您感到不舒服,则可以选择在周围保持map:
#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);
}
您需要在Java中构建native类,然后运行javah程序,该程序将构建Java期望的存根.然后,您需要将Java存根映射到C ++代码,以与您的Java程序一起编译和分发该绑定库.
/home/ehchua/programming/java/javanativeinterface.html
因此,我现在最终做的是基本上将地址存储在我的.java类中为”长”变量,然后让init()方法返回C ++实例的地址为Jlong.
然后,当我需要在类的那个实例上调用某些东西时 – 我将地址作为附加参数传递,并在这样的C代码中进行转换(在测试类/custom .SO上进行了测试):
//constructor wrapper
JNIEXPORT jlong JNICALL Java_Test_Greetings(JNIEnv *env, jobject thisObj, jint value)
{
Greetings *greetings = new Greetings(value);
return (jlong)greetings;
}
JNIEXPORT void JNICALL Java_Test_HelloWorld(JNIEnv *env, jobject thisObj, jlong reference)
{
Greetings *greetings;
greetings = (Greetings*)reference;
greetings->helloValue();
}
我不知道那是正确的方法,但是它可以奏效…如果有人告诉我我有多错.
以上所述是小编给大家介绍的JNI和构造函数,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!
原文链接:https://77isp.com/post/26152.html
=========================================
https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。
数据库技术 2022-03-28
网站技术 2022-11-26
网站技术 2023-01-07
网站技术 2022-11-17
Windows相关 2022-02-23
网站技术 2023-01-14
Windows相关 2022-02-16
Windows相关 2022-02-16
Linux相关 2022-02-27
数据库技术 2022-02-20
抠敌 2023年10月23日
嚼餐 2023年10月23日
男忌 2023年10月22日
瓮仆 2023年10月22日
簿偌 2023年10月22日
扫码二维码
获取最新动态