如何通过JNI传递对象执行回调

JNI的全称是java native interface,用来调用某些特定于系统平台或者硬件的操作,但是它只能调用c/c++的代码,若是其它语言代码,只能通过c/c++进行二次调用。
关于JNI的完整技术文档,大家可以查看下面这个网址:
 
下面我们看下JNI如何执行回调函数:
我们知道在c/c++回调函数可以通过函数指针执行,但是在Java中已经没有指针的概念,在这里,我们先传递一个类对象给native函数,然后再dll中调用期望的函数即可。
下面的这个例子中,我们通过回调传递一个字符串给java,这在java和c/c++混合编程时传递dll内部的出错或其他信息到java层是很有用的。
1.  首先创建一个java类文件,封装一个native函数和一个用于回调的函数
package  jni;

public   class  Log {

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

    
        
//用来回调,输出c代码层的信息
    public void output(String out){
               System.out.println(out);
    }

    
        
//native函数,用来传递对象
       public native void test(Log log);
    
    
public static void main(String[] args){
        Log log 
= new Log();
        
        log.test(log);    
    }

}
2.  调用javah命令,生成对应的c/c++都文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include 
< jni.h >
/* Header for class jni_Log */

#ifndef _Included_jni_Log
#define _Included_jni_Log
#ifdef __cplusplus
extern 
" C "   {
#endif
/*
 * Class:     jni_Log
 * Method:    test
 * Signature: (Ljni/Log;)V
 
*/

JNIEXPORT 
void JNICALL Java_jni_Log_test
  (JNIEnv 
*, jobject, jobject);

#ifdef __cplusplus
}

#endif
#endif
3.  利用vc和生成的头文件完成一个dll
        #include  < windows.h >

#include 
" jni_Log.h "

int  WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReasion,PVOID pvReserved)
{
    
return TRUE;
}


JNIEXPORT 
void  JNICALL Java_jni_Log_test(JNIEnv  *  env, jobject obj, jobject log)
{
    jclass cls 
= (*env)->GetObjectClass(env, log);
    jmethodID jmid 
= (*env)->GetMethodID(env, cls, "output""(Ljava/lang/String;)V");
    jstring info 
= (*env)->NewStringUTF(env, "i am a error!");
    (
*env)->CallVoidMethod(env,log, jmid,info);
    (
*env)->ReleaseStringUTFChars(env,info,(*env)->GetStringUTFChars(env, info, FALSE));
}

                 编译完成后,将mylib.dll放到与jni同级的目录中,运行命令java jni.Log,即可看到控制台成功打印信息

                "i am a error!"。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
假设我们要在 C++ 中定义一个回调函数 `onEvent`,并且在 Java 中实现一个回调接口 `MyCallback`,我们可以通过以下步骤实现 C++ 回调方法通过 JNI 反射调用 Java 回调方法: 1. 在 C++ 中定义回调函数 `onEvent`,并通过 JNI 将其注册到 Java 中: ```c++ class MyNativeClass { public: typedef void (*CallbackFunc)(int code); static void setCallback(JNIEnv* env, jobject obj, jobject callback) { jclass cls = env->GetObjectClass(callback); if (cls == NULL) return; jmethodID method = env->GetMethodID(cls, "onEvent", "(I)V"); if (method == NULL) return; callbackFunc_ = reinterpret_cast<CallbackFunc>(method); env->DeleteLocalRef(cls); callbackObj_ = env->NewGlobalRef(callback); } static void onEvent(int code) { if (callbackFunc_ != NULL && callbackObj_ != NULL) { JNIEnv* env = getJNIEnv(); env->CallVoidMethod(callbackObj_, reinterpret_cast<jmethodID>(callbackFunc_), code); } } private: static CallbackFunc callbackFunc_; static jobject callbackObj_; }; MyNativeClass::CallbackFunc MyNativeClass::callbackFunc_ = NULL; jobject MyNativeClass::callbackObj_ = NULL; extern "C" JNIEXPORT void JNICALL Java_com_example_MyClass_setCallback(JNIEnv* env, jobject obj, jobject callback) { MyNativeClass::setCallback(env, obj, callback); } ``` 2. 在 Java 中定义回调接口 `MyCallback`: ```java public interface MyCallback { void onEvent(int code); } ``` 3. 在 Java 中实现一个类 `MyClass`,并将 C++ 回调函数注册到该类中: ```java public class MyClass { static { System.loadLibrary("mylibrary"); } private static native void setCallback(MyCallback callback); public void doSomething() { // 调用 C++ 中的 onEvent 函数,触发回调 MyNativeClass.onEvent(0); } } ``` 4. 在 Java 中实现 `MyCallback` 接口并注册到 `MyClass` 中: ```java public class MyCallbackImpl implements MyCallback { @Override public void onEvent(int code) { // 处理回调事件 } } MyClass myObject = new MyClass(); myObject.setCallback(new MyCallbackImpl()); ``` 这样,当 C++ 中调用 `onEvent` 函数时,就会触发 Java 中实现的 `onEvent` 方法,从而实现了 C++ 回调方法通过 JNI 反射调用 Java 回调方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值