gpt4 book ai didi

java - 包装 C++ 对象的最佳 JNI 模式?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:40:05 26 4
gpt4 key购买 nike

我正在开发一个 Java API,其中许多 Java 对象实际上是等效 C++ 对象的包装器。 Java 对象创建 C++ 对象,并负责在不再需要它们时释放它们。我想知道为此使用的最佳模式,我可以看到两个可能的选项:

  1. 使用静态 native 方法调用和最终变量来保存 native 句柄,在构造函数中构造 C++ 对象。

    public abstract class NativeBackedObject1 implements java.lang.AutoCloseable {

    protected final long _nativeHandle;
    protected final AtomicBoolean _nativeOwner;

    protected NativeBackedObject1(final long nativeHandle) {
    this._nativeHandle = nativeHandle;
    this._nativeOwner = new AtomicBoolean(true);
    }

    @Override
    public close() {
    if(_nativeOwner.copareAndSet(true, false)) {
    disposeInternal();
    }
    }

    protected abstract void disposeInternal();
    }

    public SomeFoo1 extends NativeBackendObject1 {
    public SomeFoo1() {
    super(newFoo());
    }

    @Override
    protected final void disposeInternal() {
    //TODO: any local object specific cleanup
    disposeInternal(_nativeHandle);
    }

    private native static long newFoo();
    private native disposeInternal(final long nativeHandle);
    }
  2. 使用实例 native 方法调用和非最终变量来保存 native 句柄,在构造函数中构造 C++ 对象。

    public abstract class NativeBackedObject2 implements java.lang.AutoCloseable {
    protected long _nativeHandle;
    protected boolean _nativeOwner;

    protected NativeBackedObject2() {
    this._nativeHandle = 0;
    this._nativeOwner = true;
    }

    @Override
    public void close() {
    synchronized(this) {
    if(_nativeOwner && _nativeHandle != 0) {
    disposeInternal();
    _nativeHandle = 0;
    _nativeOwner = false;
    }
    }
    }

    protected abstract void disposeInternal();
    }

    public SomeFoo2 extends NativeBackendObject2 {
    public SomeFoo2() {
    super();
    _nativeHandle = newFoo();
    }

    @Override
    protected final void disposeInternal() {
    //TODO: any local object specific cleanup
    disposeInternal(_nativeHandle);
    }

    private native long newFoo();
    private native disposeInternal(final long nativeHandle);
    }

目前我认为 (1) 是更好的方法,因为:

  • 一个。这意味着我可以将 _nativeHandle 设置为不可变的 (final)。所以我不需要担心并发访问它或意外更改(代码实际上比这些简单的示例更复杂)。
  • b。由于构造函数,我在设计中已经正式确定,NativeBackedObject 的任何子类都是其各自 native 对象(由 _nativeHandle 表示)的所有者,因为它不能在没有它的情况下构建。

与方法 (1) 相比,方法 (2) 是否有任何优势,或者方法 (1) 是否存在任何问题?

我还可以看到方法 (1) 的替代模式,我们称之为方法 (3):

public abstract class NativeBackedObject3 implements java.lang.AutoCloseable {
protected final long _nativeHandle;
protected final AtomicBoolean _nativeOwner;

protected NativeBackedObject3() {
this._nativeHandle = newInternal();
this._nativeOwner = new AtomicBoolean(true);
}

@Override
public close() {
if(_nativeOwner.copareAndSet(true, false)) {
disposeInternal();
}
}

protected abstract long newInternal();
protected abstract void disposeInternal();
}

public SomeFoo3 extends NativeBackendObject3 {
public SomeFoo3() {
super();
}

@Override
protected final void disposeInternal() {
//TODO: any local object specific cleanup
disposeInternal(_nativeHandle);
}

@Override
protected long newInternal() {
return newFoo();
};

private native long newFoo();
private native disposeInternal(final long nativeHandle);
}

(3) 相对于 (1) 的优势在于我可以返回到默认构造函数,这有助于创建用于测试等的模拟。但主要的缺点是我无法再将额外的参数传递给newFoo().

也许还有其他我错过的方法?欢迎提出建议...

最佳答案

您是否尝试过可以生成 C++ 对象的 Java 包装器的 SWIG(http://www.swig.org)?

%typemap(javabody) SWIGTYPE %{
private long swigCPtr;
protected boolean swigCMemOwn;

public $javaclassname(long cPtr, boolean cMemoryOwn) {
swigCMemOwn = cMemoryOwn;
swigCPtr = cPtr;
}

public static long getCPtr($javaclassname obj) {
return (obj == null) ? 0 : obj.swigCPtr;
}
%}

正如 SWIG 的文档所说,考虑简单的测试类:

class Test {
string str;
public:
Test() : str("initial") {}
};

它的输出是:

public class Test {
private long swigCPtr;
protected boolean swigCMemOwn;

protected Test(long cPtr, boolean cMemoryOwn) {
swigCMemOwn = cMemoryOwn;
swigCPtr = cPtr;
}

protected static long getCPtr(Test obj) {
return (obj == null) ? 0 : obj.swigCPtr;
}

protected void finalize() {
delete();
}

// Call C++ destructor
public synchronized void delete() {
if(swigCPtr != 0 && swigCMemOwn) {
swigCMemOwn = false;
exampleJNI.delete_Test(swigCPtr);
}
swigCPtr = 0;
}

// Call C++ constructor
public Test() {
this(exampleJNI.new_Test(), true);
}

}

关于java - 包装 C++ 对象的最佳 JNI 模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34814455/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com