Можно ли ссылаться на объекты С++ в 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.