31

所以我在 C 中有以下代码,它利用了 Java Native Interface,但是我想将它转换为 C++,但我不确定如何。

 #include <jni.h>
 #include <stdio.h>
 #include "InstanceMethodCall.h"

 JNIEXPORT void JNICALL 
 Java_InstanceMethodCall_nativeMethod(JNIEnv *env, jobject obj)
 {
     jclass cls = (*env)->GetObjectClass(env, obj);
     jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "()V");
     if (mid == NULL) {
         return; /* method not found */
     }
     printf("In C\n");
     (*env)->CallVoidMethod(env, obj, mid);
 }

Java程序:

 class InstanceMethodCall {
     private native void nativeMethod();
     private void callback() {
         System.out.println("In Java");
     }
     public static void main(String args[]) {
         InstanceMethodCall c = new InstanceMethodCall();
         c.nativeMethod();
     }
     static {
         System.loadLibrary("InstanceMethodCall");
     }
 }

JNI 与 C 和 C++ 交互的区别是什么?任何帮助是极大的赞赏。

谢谢,皮特

4

4 回答 4

28

我曾经有书Essential JNI。虽然它有点过时,但其中大部分在今天仍然有效。

如果我没记错的话,在 C 中,Java 构造只是指针。因此,在您的代码中,“ (*env)->”是取消引用指针以使您可以访问底层方法。

对于 C++,“ env”实际上是一个对象——与 C 指针不同的实体。(而JNI实际上可以为你的C++代码提供真实的对象来操作,因为C++实际上是支持对象的。)所以“ env->”在C++中有不同的含义,它的意思是“调用”指向的对象中包含的方法env

我相信,另一个区别是许多 C-JNI 函数要求您的参数之一是“ JNIEnv *env”。所以在 C 中你可能不得不说(*env)->foo(env, bar). env在 c++ 中,不需要第二次引用“ ”,因此您可以改为说“ env->foo(bar)

不幸的是,我面前没有上面的书,所以我不能完全确认这一点!但我认为调查这两件事(特别是在谷歌或其他 JNI 代码中寻找它们)会让你走得很远。

于 2009-06-01T18:41:20.193 回答
8

C 和 CPP 中的 JNI 调用之间的主要区别在于:

C 风格的 JNI 看起来像 (*env)->SomeJNICall(env, param1 ...)

C++ 风格的 JNI 看起来像 env->SomeJNICall(param1 ...)

所以要将其转换为 CPP 你需要做

Java_InstanceMethodCall_nativeMethod(JNIEnv *env, jobject obj)
{
    jclass cls = env->GetObjectClass(obj);
    jmethodID mid = env->GetMethodID(cls, "callback", "()V");
    if (mid == NULL) {
        return; /* method not found */
}
printf("In C++\n");
env->CallVoidMethod(obj, mid);
//rest of your code

此外,请确保您的 JNI 函数遵循命名约定。

例子:

JNIEXPORT jint JNICALL Java_com_shark_JNITestLib_JNITestLib_startServer(JNIEnv* env, jobject o, jstring inputName, jstring streamName, jstring description) {

可以看到约定是Java_(包名)_(类名)_(方法名)

因为上面的那个是在一个类中使用的

package com.shark.JNITestLib

import java.util.stuff;

public class JNITestLib 
{
    static
    {
        System.loadLibrary("myJNIlib");
    }

    public native synchronized int startServer(String inputName, String streamName, String description);

//more class stuff...
}

在使用 JNI 时,我约定将包含 JNI 调用的类命名为与包相同的名称。这就是您看到 JNITestLib 两次的原因(这就是为什么我的 JNI 可以立即工作,因为我总是忘记如何正确命名 JNI 调用)

干杯,希望我帮助:)

于 2012-02-01T11:36:37.633 回答
5

您是否尝试过将 C 代码包装在extern "C". 请参阅C++ Faq Lite了解更多信息,以及让您将 C 代码与 C++ 一起使用的其他可能机制。

于 2009-06-01T16:36:11.547 回答
2

自从我接触标准 C++ 以来已经有一段时间了,但无论如何我都会尝试一下。

(*env)->“我觉得很奇怪。那不应该只是“ env->”吗?

也许我错了,它应该可以工作,但为什么要让事情变得更复杂呢?

于 2009-06-01T17:41:40.373 回答