我可以使用JNI在Java代码中引用C++对象吗?

2022-09-04 19:23:03

我没有在任何地方看到过这个(或者也许我只是简单地没有看到它),但是有没有办法使用JNI返回c / c ++对象并在java中使用该对象?

例如(非常简单):

class simpleClass{
...
private:
int intVar;
public:
int getIntVar();
void setIntVar(int someNum);
...
}

在我的java代码中,我将如何做这样的事情:

...
simpleClass sc = new simpleClass();
sc.setIntVar(9);
System.out.println(sc.getIntVar());
...

我意识到这是一个非常简单的例子,但我只是在寻找概念 - 我脑海中的c ++类非常大,并且希望避免创建大量的包装方法...

如果不可能,那很好,只是希望节省几天编码哈哈


答案 1

你的Java版本的SimpleClass应该做两件事。首先,保留一个私有 long 值,该值存储指向支持本机对象的 C++ 指针的值(您可能必须使用 BigInteger,具体取决于本机指针的大小 - 无符号 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();
}

然后在 JNI 代码中实现这些本机方法。该方法将新建一个支持C++ 实例。然后,该方法将删除该实例。访问器方法将使用 的值,将其转换为实际指针,并在本机支持实例上执行相应的操作。initNativeSimpleClass()SimpleClassdestroyNativeSimpleClass()nativePtr

这个成语带来了泄漏内存的真正风险,因为该类的用户在完成实例时必须调用 destroy。否则,后备本机实例可能无法正确销毁。正如我在示例中所示,您可以覆盖以调用本机破坏器函数,但是有关如何依赖finize的所有警告仍然适用。通过在销毁时将值设置为 0,可以避免在多次调用销毁时出现 seg 错误(C++删除 NULL 是安全的)。finalizenativePtr


答案 2

不,你不能。C++和Java ABI是完全不同的 - 首先,c ++没有定义一个。实际上,c ++具有如此多的功能,这些功能根本无法映射到Java,这根本无法正常工作。你期望Java如何处理c ++模板?指向基元的指针?不是指针的对象?

现在你可以做的是使用SWIG为你生成正确的包装器方法 - 这实际上会起作用,并且不会比你计划的工作多得多:)


推荐