我可以使用 JNI 在 Java 代码中引用 C++ 对象吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10212851/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can I reference C++ objects in Java Code using JNI?
提问by redhotspike
I haven't seen this anywhere (or maybe I'm jsut simple not seeing it) but is there a way to use JNI to return the c/c++ object and use that object in java?
我在任何地方都没有看到过(或者我可能只是简单地没有看到它)但是有没有办法使用 JNI 返回 c/c++ 对象并在 java 中使用该对象?
For example (very simple):
例如(非常简单):
class simpleClass{
...
private:
int intVar;
public:
int getIntVar();
void setIntVar(int someNum);
...
}
In my java code, how would I go about doing something like:
在我的 Java 代码中,我将如何做类似的事情:
...
simpleClass sc = new simpleClass();
sc.setIntVar(9);
System.out.println(sc.getIntVar());
...
I realize this is a VERY simplistic example but I'm just looking for concept - the class I have in mind that is in c++ is very large and am looking to avoid creating a TON of wrapper methods...
我意识到这是一个非常简单的例子,但我只是在寻找概念 - 我想到的 C++ 类非常大,我希望避免创建大量的包装方法......
If it's not possible that's fine, just hoping to save a few days coding lol
如果不可能,那很好,只是希望能节省几天的编码时间,哈哈
采纳答案by Voo
No you can't. The C++ and Java ABIs are completely different - for one, c++ doesn't define one. And really c++ has so many features that can't be mapped to Java at all this just can't work. How do you expect Java would handle c++ templates? Pointers to primitives? Objects that aren'tpointers?
不,你不能。C++ 和 Java ABI 是完全不同的——首先,c++ 没有定义一个。真的,c++ 有很多特性根本无法映射到 Java,这根本行不通。您期望 Java 将如何处理 C++ 模板?指向原语的指针?不是指针的对象?
Now what you can do, is use SWIG to generate the right wrapper methods for you - that will actually work and is not much more work than what you planned :)
现在您可以做的是使用 SWIG 为您生成正确的包装器方法 - 这实际上会起作用并且不会比您计划的工作多得多:)
回答by pedorro
Your Java version of SimpleClass should do two things. One, keep a private long value that stores the value of the C++ pointer to the backing native object (you might have to use BigInteger depending on how large a native pointer can be - unsigned long long?). Two, make the public methods (e.g. setIntVal
) native.
您的 Java 版本 SimpleClass 应该做两件事。一,保留一个私有 long 值,用于存储指向支持本机对象的 C++ 指针的值(您可能必须使用 BigInteger,具体取决于本机指针的大小 - unsigned long long?)。二,使公共方法(例如setIntVal
)本机。
public class SimpleClass {
private long nativePtr;
public SimpleClass() {
nativePtr = initNativeSimpleClass();
}
public void destroy() {
destroyNativeSimpleClass();
nativePtr = 0L;
}
protected void finalize() throws Throwable {
destroyNativeSimpleClass();
nativePtr = 0L;
}
public native int getIntVal();
public native void setIntVal(int val);
private native long initNativeSimpleClass();
private native void destroyNativeSimpleClass();
}
Then implement those native methods in your JNI code. The initNativeSimpleClass()
method will newa backing C++ instance of SimpleClass
. The destroyNativeSimpleClass()
method will then deletethat instance. The accessor methods will use the value of nativePtr
, cast it to a real pointer, and perform the appropriate operations on the native backing instance.
然后在您的 JNI 代码中实现这些本机方法。该initNativeSimpleClass()
方法将新建一个支持的 C++ 实例SimpleClass
。destroyNativeSimpleClass()
然后该方法将删除该实例。访问器方法将使用 的值nativePtr
,将其转换为实际指针,并在本机支持实例上执行适当的操作。
This idiom poses a real risk of leaking memory because users of the class MUST call destroy when they are done with an instance. If they don't, the backing native instance may not be properly destroyed. You can, as I've shown in the example, override finalize
to call the native destroyer function, but all the caveats about how finalize can't be relied on still apply. By setting the nativePtr
value to 0 upon destruction you avoid seg faults if destroy is called multiple times (it's safe in C++ to delete NULL).
这个习惯用法会带来内存泄漏的真正风险,因为类的用户在完成实例时必须调用 destroy 。如果不这样做,则可能无法正确销毁支持本机实例。正如我在示例中所展示的,您可以覆盖finalize
调用本机销毁器函数,但所有关于如何不能依赖 finalize 的警告仍然适用。通过nativePtr
在销毁时将该值设置为 0,您可以避免在多次调用 destroy 时出现段错误(在 C++ 中删除 NULL 是安全的)。
回答by Dan Nissenbaum
JNI defines its interface for primitive (or fairly primitive) types only, as well as memory buffer passing/management functions. There is no capability to map complex object types. However, you might be able to achieve this effect by writing your own (single) serialization/deserialization functions, as in Returning a C++ class to Java via JNI.
JNI 仅为原始(或相当原始)类型定义其接口,以及内存缓冲区传递/管理功能。没有映射复杂对象类型的能力。但是,您可以通过编写自己的(单个)序列化/反序列化函数来实现此效果,如通过 JNI 将 C++ 类返回给 Java。