JAVA学习(13) JAVA/C++互相调用 以及多线程

C++调用JAVA是JAVA的反射原理。
package com.ui.test;


import javax.swing.*;

public class test {
 private  JFrame mframe;
 private   JButton  btn;
 private   JPanel  panel;
 private    JLabel  label;
    public test() {
       mframe = new JFrame();
        mframe.setTitle("Hello");
        mframe.setSize(300, 300);

        panel = new JPanel();
        panel.setSize(100, 100);
        btn  = new JButton("按钮");
        btn.setSize(100, 100);
        panel.add(btn);
        label = new  JLabel("hello");
        panel.add(label);
        mframe.getContentPane().add(panel);
        mframe.setVisible(true);
        mframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

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

        public native String testfuc(String instring);
        void Settxt(String txt)
        {
            label.setText(txt);
        }

    public static void main(String[] srgs)
    {
        test testx = new test();
         testx.testfuc("hello");
    }

}

#include <jni.h>

void  log(char*  TAG)
{
    char buf[256] = { 0 };
    sprintf(buf, "%s:thread id %d", TAG,::GetCurrentThreadId());
    OutputDebugStringA(buf);
}
JavaVM*  javavm;
JNIEnv * envm;
jobject obj;
int x = 0;
char buf[25];
DWORD  __stdcall  th2(void* lp)
{
    log("th2 begin");
    JNIEnv*  env;
    javavm->AttachCurrentThread((void**)(&env), NULL);
    log("th2 end"); 
    while (true)
    {
        sprintf(buf, "%d", x * 10);
        jstring rtstr2 = env->NewStringUTF(buf);
        env->GetObjectClass(obj);
        jclass cl = env->GetObjectClass(obj);
        jmethodID  id = env->GetMethodID(cl, "Settxt", "(Ljava/lang/String;)V");
        env->CallVoidMethod(obj, id, rtstr2);
        x++;
        Sleep(1000);
    }
    return 0;
}
DWORD  __stdcall  th(void* lp)
{
    ::CreateThread(NULL, 0, LPTHREAD_START_ROUTINE(th2), NULL, 0, 0);
    log("th1 begin");
    JNIEnv*  env;
    javavm->AttachCurrentThread((void**)(&env), NULL);

    log("th1 end");
    while (true)
    {
        sprintf(buf, "%d", x * 10);
        jstring rtstr2 = env->NewStringUTF(buf);
        env->GetObjectClass(obj);
        jclass cl = env->GetObjectClass(obj);
        jmethodID  id = env->GetMethodID(cl, "Settxt", "(Ljava/lang/String;)V");
        env->CallVoidMethod(obj, id, rtstr2);
        x++;
        Sleep(1000);
    }

    return 0;
}
static jstring JNICALL Test(JNIEnv *env, jobject arg, jstring instring)
{
    envm = env; 
    const char *str = (const char *)env->GetStringUTFChars(instring, JNI_FALSE); 
    env->ReleaseStringUTFChars(instring, str);
    x++;
    sprintf(buf, "%d", x);
    jstring rtstr = env->NewStringUTF(buf);
    sprintf(buf, "%d", x*10);
    jstring rtstr2 = env->NewStringUTF(buf);



    jclass cl = env->GetObjectClass(arg);
    jmethodID  id= env->GetMethodID(cl, "Settxt", "(Ljava/lang/String;)V");
    env->CallVoidMethod(arg, id, rtstr2);
    obj= env->NewGlobalRef(arg);
    ::CreateThread(NULL, 0, LPTHREAD_START_ROUTINE(th), NULL, 0, 0);
    return rtstr;
}
static const JNINativeMethod gMethods[] = { //定义批量注册的数组,是注册的关键部分
    { "testfuc", "(Ljava/lang/String;)Ljava/lang/String;", (void*)Test } // func2是在java中声明的native函数名,"()V"是函数的签名,可以通过javah获取。
};
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void *reserved) //这是JNI_OnLoad的声明,必须按照这样的方式声明
{
    javavm = vm;

    JNIEnv* env = NULL; //注册时在JNIEnv中实现的,所以必须首先获取它
    jint result = -1;

    if (vm->GetEnv(  (void**)&env, JNI_VERSION_1_4) != JNI_OK) //从JavaVM获取JNIEnv,一般使用1.4的版本
        return -1;


    jclass clazz;
    static const char* const kClassName = "com/ui/test/test";

    clazz =env->FindClass(kClassName); //这里可以找到要注册的类,前提是这个类已经加载到java虚拟机中。 这里说明,动态库和有native方法的类之间,没有任何对应关系。

    if (clazz == NULL)
    {
        ::MessageBoxA(0, "JNI_OnLoad", kClassName, 0);
        return -1;
    }


    if (env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK) //这里就是关键了,把本地函数和一个java类方法关联起来。不管之前是否关联过,一律把之前的替换掉!
    {
        printf("register native method failed!\n");
        return -1;
    }

    return JNI_VERSION_1_4; //这里很重要,必须返回版本,否则加载会失败。
}
  1. JNI_OnLoad 保存JavaVM指针
  2. 在JAVA调用在JAVA调用C++时,保存JAVA对象,obj= env->NewGlobalRef(arg)使得对象可以全局共享
  3. 多线程中使用javavm->AttachCurrentThread 附加线程到Java线程中
  4. 附加线程后,使用env->GetObjectClass(obj) 获取对象的class
  5. AttachCurrentThread 不会立刻修改线程id,不知什么原理
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值