Java调用C调用Java

时间:2011-03-23 20:32:27

标签: java c java-native-interface

我想使用JNI从Java调用C函数。在C函数中,我想创建一个JVM并调用一些Java对象。当我尝试创建JVM时,JNI_CreateJavaVM返回-1。

所以,我想知道是否可以这样做。编译C代码以创建.so文件(在linux中),Java代码调用.so文件中的函数。

任何使用Java-> C-> Java的例子都很有用。

感谢。

4 个答案:

答案 0 :(得分:2)

不,不幸的是,这是不可能的。每个进程只能有一个JVM,并且您已经处于JVM进程中。

答案 1 :(得分:2)

我无法看到Java中的重点 - > C - > Java。

如果可以从Java调用C,那么可以在C函数返回后从Java调用Java。

Excelsion xFunction是一个简单可靠的库,用于从Java调用C语言。它处理奇怪的JNI内容,为您提供更简单的界面。

答案 2 :(得分:2)

为什么需要创建第二个JVM?您无法创建第二个JVM,但可以从C代码访问Java类。请参阅Accessing Java Objects

答案 3 :(得分:1)

我不明白为什么有些人认为这无用。实际上,Java - > C - >进入Android游戏编程时,Java场景很常见:

  1. Android应用程序从一些用Java编写的样板代码开始(使用SDK)
  2. 启动一个新线程来运行游戏的主要逻辑,该逻辑用C / C ++编写以提高效率(并且更容易访问OpenGL ES
  3. C / C ++代码调用一些Java方法来实现所需的功能
  4. 有必要使用SDK (Java)的原因是大多数Android API仅以Java提供! NDK (C / C++)仅提供了一个纤薄的Linux环境(将其视为“标准C库”+“标准C ++库”+“Linux系统库的缩减版”)。例如,如果要将应用程序与AdMob (Google Ads)In-app Billing (Google Payment)集成,或者如果要访问设备的内置摄像头,则必须从游戏逻辑中调用Java方法(写的是C / C ++!)。

    Java - > C部分

    编写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 - &gt; Java部分

    由于您使用Java(而不是C / C ++)启动了程序,因此已经创建了一个JVM。您不需要在第二部分(C - > Java部分)中创建另一部分,您只需要重用已创建的部分。有两种方法可以做到:

    1. 使用第一部分(Java - &gt; C部分)的JNI调用提供的Java环境指针(JNIEnv*
    2. 使用在JavaVM*
    3. 期间保存的Java虚拟机指针(JNI_OnLoad()

      (答案尚未完成,我稍后会完成。如果您喜欢,请投票给我鼓励。谢谢!)

      参考文献: