JNI和构造函数 [英] JNI and constructors
问题描述
我有一个需要在项目中使用的编译库。为了简短起见,它是一个用于与特定硬件交互的库。我所拥有的是.a和.dll库文件,分别用于linux和Windows,还有一堆带有所有公共函数和类的C ++ .h标头。
I have a compiled library that I need to use in a project. To keep it short, it's a library for interacting with a specific piece of hardware. What I have is .a and .dll library files, for linux and windows respectively, and a bunch of C++ .h headers with all the public functions and classes described there.
问题在于该项目需要使用Java,因此我需要为此库编写一个JNI包装器,老实说,我从来没有做过。
The problem is that the project needs to be in Java, so I need to write a JNI wrapper for this library, and honestly, I've never done that. But that's ok, I'm down to learn the thing.
我已经在线阅读了很多文档,并且找出了传递变量,并从中创建java对象的方法。
I've read up a bunch of documentation online, and I figured out passing variables, creating java objects from native code, etc.
本机代码等。
我不知道,如何使用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);
So basically if I was to write my program in C++ (which I can't), I would do something like
所以基本上,如果我要用C ++编写程序(我不能),我会做类似的事情
RFEthernetDetector ethernetDetector = new RFEthernerDetector(somePort);
and then work with that object. But... How do I do this in Java using JNI?
I don't understand how am I supposed to create a native method for constructor, that would call the constructor from my .a library, and then have some way of working with that specific object? I know how to create java objects from native code - but the thing is I don't have any information about internal structure of the RFEthernetDetector class - only some of it's public fields and public methods.
然后使用该对象。但是...如何在Java中使用JNI做到这一点?
我不明白如何为构造函数创建本机方法,该方法会从我的.a库中调用构造函数,然后使用某种方式处理该特定对象?我知道如何从本机代码创建Java对象-但问题是我没有关于RFEthernetDetector类的内部结构的任何信息-只有一些公共字段和公共方法。
And I can't seem to find the right articles on the net to help me out. How do I do that?
在网上似乎找不到合适的文章对我有帮助。我该怎么做?
Update: A bit further clarification.
更新:需要进一步澄清。
I create a .java wrapper class like this:
我创建一个.java包装类。像这样:
public class RFEthernetDetector
{
public RFEthernetDetector(int portNumber)
{
Init(portNumber);
}
public native void Init(int portNumber); // Void? Or what?
}
then I compile it with -h parameter to generate JNI .h file:
然后我用-h参数编译它以生成JNI .h文件: / p>
/* 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 then create an implementation that will call the functions from my .a library:
然后创建一个实现,该实现将从我的.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类,它通过指针拥有在C ++端具有 RFEthernetDetector
。 这很有趣,但是语言间的粘合从来都不是。
// 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
处理都使您感到不舒服,则可以选择保留地图
:
If all that reinterpret_cast
ing makes you feel uncomfortable, you could choose to instead keep a 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);
}
这篇关于JNI和构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!