2012-04-18 18 views
11

Nie widziałem tego nigdzie (a może jestem jsut prosty, nie widząc tego), ale czy istnieje sposób na użycie JNI do zwrócenia obiektu c/C++ i użycia tego obiektu w java?Czy mogę odwoływać się do obiektów C++ w kodzie Java za pomocą JNI?

Na przykład (bardzo prosty):

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

W moim kodu java, jak bym go o zrobienie czegoś jak:

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

zdaję sobie sprawę że jest to bardzo uproszczony przykład, ale I” Po prostu szukam pojęcia - klasa, którą mam na myśli, która jest w C++ jest bardzo duża i staram się unikać tworzenia TON wrapper metod ...

Jeśli to nie jest w porządku, po prostu chmiel Aby zapisać kilka dni kodowania lol

Odpowiedz

7

Nie możesz. ABI w C++ i Java są zupełnie inne - dla jednego C++ nie definiuje jednego. A naprawdę C++ ma tak wiele funkcji, których nie można zmapować na Javę w ogóle, to po prostu nie działa. Jak można oczekiwać, że Java będzie obsługiwać szablony C++? Wskaźniki dla prymitywów? Obiekty, które są , nie są wskaźnikami?

Teraz to, co można zrobić, to użycie SWIG wygenerować odpowiednie metody otoki dla siebie - że będzie faktycznie pracują i nie jest dużo więcej pracy niż to, co planowano :)

+4

Należy pamiętać, że szablony C++ są nieistotne dla tego pytania, ponieważ szablony są kompilowane w C++. JNI będzie musiał obsługiwać klasy utworzone z tych szablonów, które nie różnią się od zwykłych klas. –

+0

@Dan Jeśli napiszesz klasę szablonu, która nie jest tylko nagłówkiem, musisz być w stanie powiedzieć kompilatorowi, jak utworzyć nową wersję klasy w kodzie klienta, więc myślę, że kompilator musi również wiedzieć o szablonach (choć nie mam pojęcia, czy jest to wymagane przez standard - nigdy nie musiałem tego robić w rzeczywistości). – Voo

+0

@ Voo Potrzebuje definicji szablonu podczas kompilacji, aby wygenerować instancję. Po wygenerowaniu dla każdego potrzebnego użytego typu kod obiektowy jest taki, jak gdybyś napisał klasy dla każdego typu. AFAIK bez dołączania pliku cpp, do którego nie możesz odwoływać się do szablonu, który nie znajduje się w twojej jednostce tłumaczeniowej, chyba że definicja jest całkowicie wbudowana z tego samego powodu. – AJG85

0

JNI definiuje jego interfejs prymitywny (lub dość prymitywne) tylko typy, jak również funkcje przekazywania/zarządzania buforem pamięci. Nie ma możliwości mapowania złożonych typów obiektów. Jednak możesz osiągnąć ten efekt, pisząc własne (pojedyncze) funkcje szeregowania/deserializacji, jak w przypadku Returning a C++ class to Java via JNI.

+0

ciekawe ... to bardzo ciekawa koncepcja. Doceniam ten link! Dzięki! – redhotspike

12

Twoja wersja SimpleClass w Javie powinna zrobić dwie rzeczy. Po pierwsze, zachowaj prywatną długą wartość, która przechowuje wartość wskaźnika C++ do natywnego obiektu bazowego (może być konieczne użycie BigInteger w zależności od tego, jak duży może być natywny wskaźnik - niepodpisany długo?). Po drugie, uczyń publiczne metody (na przykład setIntVal) natywne.

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(); 
} 

Następnie zaimplementuj te natywne metody w kodzie JNI. Metoda initNativeSimpleClass() będzie nowa z backfunkcją C++ z SimpleClass. Metoda destroyNativeSimpleClass() następnie usunie z tej instancji. Metody uzyskujące dostęp będą używać wartości nativePtr, przesyłają ją do rzeczywistego wskaźnika i wykonują odpowiednie operacje na macierzystej instancji kopii.

Ten idiom stanowi realne ryzyko przeciekania pamięci, ponieważ użytkownicy klasy MUSZĄ wywoływać niszczą, gdy są wykonywane z instancją. Jeśli tego nie zrobią, natywna instancja podkładu może nie zostać odpowiednio zniszczona. Możesz, jak pokazałem w tym przykładzie, zastąpić finalize, aby zadzwonić do natywnej funkcji niszczyciela, ale wszystkie zastrzeżenia dotyczące tego, w jaki sposób nie można polegać na finalizacji, nadal mają zastosowanie. Ustawiając wartość nativePtr na 0 po zniszczeniu, unikniesz błędów seg, jeśli destrukt zostanie wywołany wiele razy (jest to bezpieczne w C++, aby usunąć NULL).

+0

Pozwala to uniknąć tworzenia funkcji opakowania, ale jest to naprawdę jedyny sposób na użycie JNI do umieszczenia kodu Java na klasach natywnych. – pedorro

+0

Zdecydowanie podoba mi się to, co zaproponowałem ... Muszę powiedzieć, że I tak lepiej niż "używanie" obiektu C++: zapewnia sposób dokumentowania, że ​​używam natywnych metod. Dzięki! – redhotspike

Powiązane problemy