Java, вызывающая C, вызывающая Java - PullRequest
5 голосов
/ 23 марта 2011

Я хочу вызвать функцию C из Java, используя JNI. А в функции C я хочу создать JVM и вызвать некоторые объекты Java. Когда я пытаюсь создать JVM, JNI_CreateJavaVM возвращает -1.

Итак, я хочу знать, возможно ли это сделать. Код C компилируется для создания файла .so (в linux), а код Java вызывает функцию в файле .so.

Будет полезен любой пример выполнения Java-> C-> Java.

Спасибо.

Ответы [ 4 ]

2 голосов
/ 23 марта 2011

Я не вижу смысла в том, что Java -> C -> Java.

Если вы можете вызвать C из Java, то вы можете вызвать Java из Java после того, как ваша функция C вернется.

Excelsion xFunction - это простая и надежная библиотека для вызова C из Java.Он обрабатывает странные вещи JNI, предоставляя вам более простой интерфейс.

2 голосов
/ 23 марта 2011

Зачем вам нужно создавать вторую JVM?Вы не можете создать вторую JVM, но вы можете получить доступ к классам Java из кода C.См. Доступ к объектам Java .

2 голосов
/ 23 марта 2011

Нет, к сожалению, это невозможно. Вы можете иметь только одну JVM на процесс, и вы уже находитесь в процессе JVM.

1 голос
/ 02 марта 2013

Я не понимаю, почему некоторые люди считают это бесполезным. На самом деле сценарий Java -> C -> Java очень распространен, когда вы начинаете программировать игры для Android:

  1. Приложение Android запускается с некоторого стандартного кода, написанного на Java (с использованием SDK)
  2. Запущен новый поток для запуска основной логики игры, которая написана на C / C ++ для повышения эффективности (и облегчения доступа к OpenGL ES )
  3. Код C / C ++ вызывает некоторые методы Java для требуемой функциональности

Причина, по которой необходимо использовать SDK (Java) , заключается в том, что большинство API-интерфейсов Android предоставляются только на Java! NDK (C / C ++) предоставляет только тонкую среду Linux (воспринимается как «Стандартная библиотека C» + «Стандартная библиотека C ++» + «Сокращенная версия системных библиотек Linux»). Например, если вы хотите интегрировать свое приложение с AdMob (Google Ads) или Биллинг в приложении (Google Payment) , или если вы хотите получить доступ к встроенной камере устройства, вы должны вызывать методы Java из игровой логики (которая написана на C / C ++!).

Java -> C Part

Написать класс Java. Объявите один метод native:

$ ls -F1
classes/
jni/
src/

$ nano src/com/example/jcj/Test.java

Test.java:

package com.example.jcj;

public class Test {
    public static void main(String[] args) {
        doSomethingInC();
    }

    public static native void doSomethingInC();

    public static void doSomethingInJava() {
        System.out.println("Done something in Java!");
    }

    static {
        System.loadLibrary("hello_jcj");
    }
}

Вызовите «Java-компилятор» (javac), а затем «Генератор заголовочных файлов и заглушек C» (javah):

$ javac -sourcepath src -d classes src/com/example/jcj/Test.java

$ javah -classpath classes -d jni com.example.jcj.Test

$ ls -F1 jni/
com_example_jcj_Test.h

Реализация части C:

$ nano jni/com_example_jcj_Test.c

com_example_jcj_Test.c:

#include "com_example_jcj_Test.h"
#include <stdio.h>

/*
 * Class:     com_example_jcj_Test
 * Method:    doSomethingInC
 * Signature: ()V
 */
JNIEXPORT void JNICALL
Java_com_example_jcj_Test_doSomethingInC(JNIEnv* env, jclass clazz)
{
    printf("Done something in C!\n");
}

Скомпилируйте источник C (Windows):

> REM TODO: Add this!

Скомпилируйте источник C (Linux):

$ gcc -I{JAVA_HOME}/include
      -shared \
      -o libhello_jcj.so \
      jni/com_example_jcj_Test.c

$ ls -F1
classes/
jni/
libhello_jcj.so*
src/

Скомпилируйте источник C (Mac OS X):

$ gcc -I${JAVA_HOME}/include \
      -shared \
      -o libhello_jcj.jnilib \
      jni/com_example_jcj_Test.c

$ ls -F1
classes/
jni/
libhello_jcj.jnilib*
src/

Запустите приложение Java:

$ java -classpath classes com.example.jcj.Test
Done something in C!

C -> Часть Java

Поскольку вы запустили свою программу на Java (а не на C / C ++), JVM уже создана. Вам не нужно создавать еще одну во второй части (C -> часть Java), вам просто нужно повторно использовать уже созданную. Есть 2 способа сделать это:

  1. Используя указатель среды Java (JNIEnv*), предоставленный вызовом JNI из первой части (Java -> часть C)
  2. Используя указатель виртуальной машины Java (JavaVM*), сохраненный во время JNI_OnLoad()

(Ответ не закончен, и я закончу его позже. Если вам это нравится, пожалуйста, проголосуйте за поддержку. Спасибо!)

Ссылки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...