Можно ли ссылаться на объекты С++ в Java-коде с помощью JNI?

Я ничего не видел (или, может быть, я просто не вижу его), но есть ли способ использовать JNI для возврата объекта 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());
...

Я понимаю, что это ОЧЕНЬ упрощенный пример, но я просто ищу концепцию - класс, который я имею в виду, который находится на С++, очень большой, и я стараюсь избегать создания TON методов-оберток...

Если это невозможно, это прекрасно, просто надеясь сохранить несколько дней кодирования lol

Ответ 1

Нет, вы не можете. С++ и Java ABI совершенно разные - для одного, С++ не определяет один. И на самом деле С++ имеет так много функций, которые не могут быть сопоставлены с Java при этом просто не могут работать. Как вы ожидаете, что Java будет обрабатывать шаблоны С++? Указатели на примитивы? Объекты, которые не являются указателями?

Теперь, что вы можете сделать, используется SWIG для создания правильных методов обертки для вас - это будет действительно работать и не намного больше, чем вы планировали:)

Ответ 2

Ваша версия Java SimpleClass должна делать две вещи. Во-первых, сохраняйте частное длинное значение, которое хранит значение указателя С++ для основного объекта поддержки (вам может потребоваться использовать 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();
}

Затем реализуйте эти собственные методы в коде JNI. Метод initNativeSimpleClass() будет иметь новый экземпляр С++ для поддержки SimpleClass. Метод destroyNativeSimpleClass() затем удалит этот экземпляр. Методы доступа будут использовать значение nativePtr, перевести его в реальный указатель и выполнить соответствующие операции над исходным экземпляром.

Эта идиома представляет реальный риск утечки памяти, потому что пользователи класса ДОЛЖНЫ называть destroy, когда они выполняются с экземпляром. Если они этого не сделают, основной экземпляр поддержки может быть неправильно уничтожен. Вы можете, как я показал в примере, переопределить finalize, чтобы вызвать функцию родного эсминец, но все предостережения о том, как завершить работу, нельзя полагаться на по-прежнему. Установив значение nativePtr равным 0 при уничтожении, вы избегаете seg-сбоев, если destroy вызывается несколько раз (он безопасен в С++ для удаления NULL).

Ответ 3

JNI определяет свой интерфейс только для примитивных (или довольно примитивных) типов, а также для функций передачи/управления буфером памяти. Нет возможности сопоставлять сложные типы объектов. Однако вы можете добиться этого эффекта, написав собственные (одиночные) функции сериализации/десериализации, как в Возвращение класса С++ на Java через JNI.