本文介绍了JNI和构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个需要在项目中使用的编译库。为了简短起见,它是一个用于与特定硬件交互的库。我所拥有的是.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 __cplusplusextern "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_casting 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和构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-18 06:01