day07_JNI

作者: 闪客飞飞 | 来源:发表于2021-02-03 20:51 被阅读0次

    JNI(Java Native Interface)
    Java调用C/C++,C/C++调用Java的一套API

    1.编写native方法
    2.javah命令,生成.h头文件
    3.复制.h头文件到CPP工程中
    4.复制jni.h和jni_md.h文件到CPP工程中
    5.实现.h头文件中声明的函数
    6.生成dll文件
    7.配置dll文件所在目录到环境变量
    8.重启Eclipse

    C的函数名称:Java_完整类名_函数名

    .
    .dll 共享代码

    程序->打包包含 静态库 打包不会包含动态库dll

    JNIEnv :代表java 运行环境,调用java中的代码
    在C 中
    JNIEnv 结构体指针
    env C中二级指针
    (*env)->NewStringUTF(env,"chegnuye");

    在C++中
    JNIEnv 在C++ 中就是一个结构体的别名
    env C++中一级指针
    env->NewStringUTF("chengyue");

    在C/C++中为什么不一样?
    C++ 中仍然用的C 的结构体

    //JNIEnv结构体的指针别名
    typedef struct JNINativeInterface_* JNIEnv;

    //结构体
    struct JNINativeInterface_ {
    char* (NewStringUTF)(JNIEnv, char*);
    };

    //函数实现
    char* NewStringUTF(JNIEnv* env, char* str){
    //在NewStringUTF执行过程,仍然需要JNIEnv
    return str;
    }

    void main(){
    //实例化结构体
    struct JNINativeInterface_ struct_env;
    struct_env.NewStringUTF = NewStringUTF;

    //结构体指针
    JNIEnv e = &struct_env;
    
    //结构体的二级指针
    JNIEnv *env = &e;
    
    //通过二级指针调用函数
    char* str = (*env)->NewStringUTF(env,"abc");
    

    }

    java Code:
    package com.test.cy;

    import java.util.Date;
    import java.util.Random;
    import java.util.UUID;

    public class JniTest {
    public static void main (String args[]) {
    JniTest t=new JniTest();
    // String str=t.getStringFromC();//返回字符串
    // System.out.print("getStringFromC"+str);

    // String test=t.getString2Fromc(6);//返回字符串 带参数
    // System.out.print("getString2Fromc"+test);

    // System.out.print("key="+t.key+"\n");//访问 属性
    // System.out.print("accrssField\n"+t.accrssField()+"\n");
    // System.out.print("update key="+t.key);

    // System.out.print("count="+count+"\n"); // 访问静态属性
    // t.accrssStaticField();
    // System.out.print("update count="+count+"\n");

    // t.accessMethod(); //访问Java 方法

    // t.accessStaticMethod(); //访问静态方法

        Date d=t.accessConstructor(); //JNI 访问静态方法返回一个时间戳
        System.out.print("d="+d);
    }
    public String key="vc++";
    public static int count=9;
    // 访问属性
    public native String getStringFromC();
    public native String getString2Fromc(int t);
    public native String accrssField();
    public native void accrssStaticField();
    public native void accessMethod();
    public native void accessStaticMethod();
    public native Date accessConstructor();
    //产生指定范围的随机数
    public int genRandimInt(int max) {
        System.out.print("max="+max);
        return new Random().nextInt(max);
    }
    //产生UUID 字符串
    public static String getUUID() {
        return UUID.randomUUID().toString();
    }
    //加载动态库
    static {
        System.loadLibrary("Project4");
    }
    

    }

    C Head:
    /* DO NOT EDIT THIS FILE - it is machine generated */

    include "jni.h"

    /* Header for class com_test_cy_JniTest */

    ifndef _Included_com_test_cy_JniTest

    define _Included_com_test_cy_JniTest

    ifdef __cplusplus

    extern "C" {

    endif

    /*

    • Class: com_test_cy_JniTest
    • Method: getStringFromC
    • Signature: ()Ljava/lang/String;
      */
      JNIEXPORT jstring JNICALL Java_com_test_cy_JniTest_getStringFromC
      (JNIEnv , jclass);
      /
    • Class: com_test_cy_JniTest
    • Method: getString2Fromc
    • Signature: ()V
      */
      JNIEXPORT jstring JNICALL Java_com_test_cy_JniTest_getString2Fromc
      (JNIEnv *, jobject,jint);
      JNIEXPORT jstring JNICALL Java_com_test_cy_JniTest_accrssField
      (JNIEnv *, jobject);
      JNIEXPORT void JNICALL Java_com_test_cy_JniTest_accrssStaticField
      (JNIEnv *, jobject);
      JNIEXPORT void JNICALL Java_com_test_cy_JniTest_accessMethod
      (JNIEnv *, jobject);
      JNIEXPORT void JNICALL Java_com_test_cy_JniTest_accessStaticMethod
      (JNIEnv *, jobject);

    ifdef __cplusplus

    }

    endif

    endif

    C .c

    define _CRT_SECURE_NO_WARNINGS

    include "com_test_cy_JniTest.h"

    include <Windows.h>

    include <string.h>

    include <stdio.h>

    //函数实现
    JNIEXPORT jstring JNICALL Java_com_test_cy_JniTest_getStringFromC
    (JNIEnv env, jclass jcls)
    {
    //打开 桌面 应用
    WinExec("D:\QQmusic\QQMusic.exe", 0);
    //简单实现
    return (
    env)->NewStringUTF(env, "chengyuet_wwwwTEST");
    }

    JNIEXPORT jstring JNICALL Java_com_test_cy_JniTest_getString2Fromc
    (JNIEnv env, jobject j,jint i){
    printf("\nlog---%d",i);
    return (
    env)->NewStringUTF(env, "---" );
    }

    //每个native 函数 都至少有两个函数 一个是JniEnv 的指针 另一个是 jclass 或者 jobject
    //当native 方法为静态方法时
    //jclass 代表native 方法所属类的class 对象 (JniTest.class)
    //当native 方法为非静态方法
    //jobject 代表native 方法所属的对象

    //Jni基本数据类型
    //java基本数据类型 与 JNI基本数据类型的映射关系
    //java 类型 ->jni类型 ->C 类型

    //typedef unsigned char jboolean;
    //typedef unsigned short jchar;
    //typedef short jshort;
    //typedef float jfloat;
    //typedef double jdouble;
    //typedef jint jsize;

    //引用类型(对象)
    //String jstring
    //object jobject
    //数组,基本数据类型的数组
    //byte[] jByteArray
    //对象数组
    //object jobjectArray

    //C/C++访问Java的成员 修改属性Key
    JNIEXPORT jstring JNICALL Java_com_test_cy_JniTest_accrssField
    (JNIEnv env, jobject jobject){
    //得到jclass
    jclass cls=(
    env)->GetObjectClass(env,jobject);
    //得到jfieldID
    jfieldID jfd = (env)->GetFieldID(env, cls, "key", "Ljava/lang/String;");
    //vc++ -> chengyue 获取这个对象的值 Get<Type>Field
    jstring jstr = (
    env)->GetObjectField(env, jobject, jfd);
    //jstring s 转成C 的字符串
    //isCopy 是否复制的意思
    char c_str = (env)->GetStringUTFChars(env, jstr, NULL);
    //拼接成新的字符串
    char text[20] = "super ";
    strcat(text, c_str);
    //c 字符串 转 Jstring
    jstring ss = (env)->NewStringUTF(env, text);
    //修改key Set<Type>Field
    (
    env)->SetObjectField(env, jobject, jfd, ss);
    return ss;
    }

    //访问静态属性
    JNIEXPORT void JNICALL Java_com_test_cy_JniTest_accrssStaticField
    (JNIEnv *env, jobject jobject){

    //jclass 
    jclass cls = (*env)->GetObjectClass(env, jobject);
    //jfield
    jfieldID jfd = (*env)->GetStaticFieldID(env, cls, "count", "I");
    //jInt
    jint i=(*env)->GetStaticIntField(env, cls, jfd);
    i++;
    (*env)->SetStaticIntField(env, cls, jfd, i);
    

    }

    //访问java 方法
    JNIEXPORT void JNICALL Java_com_test_cy_JniTest_accessMethod
    (JNIEnv env, jobject jobject){
    jclass jls=(
    env)->GetObjectClass(env, jobject);
    jmethodID jmd = (env)->GetMethodID(env, jls, "genRandimInt", "(I)I");
    //Call<Type>Method
    jint i=(
    env)->CallIntMethod(env, jobject, jmd, 200);
    printf("%ld,", i);
    }

    //静态方法
    JNIEXPORT void JNICALL Java_com_test_cy_JniTest_accessStaticMethod
    (JNIEnv env, jobject jobject){
    jclass jls = (
    env)->GetObjectClass(env, jobject);
    jmethodID jmd = (*env)->GetStaticMethodID(env, jls, "getUUID", "()Ljava/lang/String;");

    //调用
    jstring uuid = (*env)->CallStaticObjectMethod(env, jls, jmd);
    
    //随机文件名称  uuid.txt
    //jstring 转成 char *   isCopy  JNI_false Java C 操作的同一个字符串
    char* uuid_name=(*env)->GetStringUTFChars(env, uuid, JNI_FALSE);
    
    //拼接
    char fileName[100];
    sprintf(fileName, "F://%s.txt", uuid_name);
    FILE *fp = fopen(fileName, "w");
    fputs("i love code123", fp);
    fclose(fp);
    

    };

    //访问构造方法
    //使用java.util.date 产生一个当前的时间戳对象
    JNIEXPORT jobject JNICALL Java_com_test_cy_JniTest_accessConstructor
    (JNIEnv env, jobject job){
    jclass cls = (
    env)->FindClass(env, "java/util/Date");
    //jmethid 构造 方法 ()V
    jmethodID constructor_mid = (env)->GetMethodID(env, cls, "<init>", "()V");
    //实例化一个Date对象
    jobject date_obj = (
    env)->NewObject(env, cls, constructor_mid);
    //调用getTime方法
    jmethodID mid = (env)->GetMethodID(env, cls, "getTime", "()J");
    jlong time = (
    env)->CallLongMethod(env, date_obj, mid);
    printf("\ntime:%lld\n", time);
    return date_obj;
    }

    //访问父类的方法
    JNIEXPORT void JNICALL Java_com_test_cy_JniTest_accessNonvirtualMethod
    (JNIEnv env, jobject job){
    //获取man 属性
    jclass cls = (
    env)->GetObjectClass(env, job);
    jfieldID jfd = (env)->GetFieldID(env, cls, "man", "Lcom/test/cy/Human;");
    jobject obj = (
    env)->GetObjectField(env, job, jfd);
    //执行sayHi 方法
    jclass human_class = (env)->FindClass(env, "com/test/cy/Human");
    jmethodID mid = (
    env)->GetMethodID(env, human_class, "sayHi", "()V");
    //执行
    //(env)->CallObjectMethod(env, obj, mid);
    //调用父类的方法 覆盖
    (
    env)->CallNonvirtualObjectMethod(env, obj, human_class, mid);
    }
    //访问父类的方法
    JNIEXPORT void JNICALL Java_com_test_cy_JniTest_accessNonvirtualWomenMethod
    (JNIEnv env, jobject jobjectb){
    jclass jls = (
    env)->GetObjectClass(env, jobjectb);
    jfieldID jfid = (env)->GetFieldID(env, jls, "women", "Lcom/test/cy/Human;");
    jobject jobj_wo = (
    env)->GetObjectField(env, jobjectb, jfid);
    //执行方法
    jclass humon_class = (env)->FindClass(env, "com/test/cy/Human");
    jmethodID mid = (
    env)->GetMethodID(env, humon_class, "sayHi", "()V");
    //(env)->CallObjectMethod(env, jobj_wo, mid);//执行子类的方法
    (
    env)->CallNonvirtualObjectMethod(env, jobj_wo, humon_class, mid);//执行父类的方法
    }
    //中文问题
    JNIEXPORT jstring JNICALL Java_com_test_cy_JniTest_chineseChars
    (JNIEnv *env, jobject jo, jstring js){
    //输出
    char jsd = (env)->GetStringUTFChars(env, js, JNI_FALSE);
    printf("%s\n", jsd);
    //返回中文異常
    char str = "马伊意义嘛嘛嘛";
    //return (
    env)->NewStringUTF(env,str);

    //執行 String 需要的条件
    //1.jmethodID
    //2. byte 数组  字符数组 编码
    jclass jls=(*env)->FindClass(env, "java/lang/String");
    jmethodID jmd=(*env)->GetMethodID(env, jls,"<init>", "([BLjava/lang/String;)V");
    
    //jbyte  ->char    相对应
    jbyteArray jba = (*env)->NewByteArray(env, strlen(str));
    //byte 数组赋值
    (*env)->SetByteArrayRegion(env, jba, 0, strlen(str), str);
    
    //字符编码jstring
    jstring charsetName = (*env)->NewStringUTF(env,"GB2312");
    return (*env)->NewObject(env, jls, jmd, jba, charsetName);
    

    }
    int compare(int a, int b){
    return (
    b) - (
    a);
    }
    //数组
    JNIEXPORT void JNICALL Java_com_test_cy_JniTest_giveArray
    (JNIEnv env, jobject jo, jintArray jia){
    // jintArray ->jint 指针 -》 c int 数组
    jint elems=(env)->GetIntArrayElements(env, jia, NULL);
    //数组长度
    int len = (
    env)->GetArrayLength(env, jia);
    //函数指针
    //数组排序
    qsort(elems, len, sizeof(jint), compare);
    //同步 mode 0: java 数组进行更新,并且释放从C/C++数组
    // model 1: JNI_ABORT : java 数组不更新。释放从C/ C++数组
    // model 2: JNI_COMMENT: java 数组进行更新。不释放从C/ C++数组
    (*env)->ReleaseIntArrayElements(env, jia, elems,0);
    }

    //返回数组
    JNIEXPORT jintArray JNICALL Java_com_test_cy_JniTest_getArray
    (JNIEnv env, jobject jo, jint ji){
    jintArray jia = (
    env)->NewIntArray(env,ji);
    jint element = (env)->GetIntArrayElements(env, jia, NULL);
    int i = 0;
    for (; i < ji; i++){
    element[i] = i;
    }
    (*env)->ReleaseIntArrayElements(env, jia, element, 0);
    return jia;
    }

    //JNI引用变量
    //引用类型:局部引用和全局引用
    //作用:在JNI中告诉虚拟机合适回收一个JNI变量

    //局部引用 通过deleteLocalRef()手动释放对象
    // 1.访问一个很大的java对象,使用完后还要进行复杂的操作。
    // 2.创建了太多的局部引用,并且和后边代码没有关联性

    //模拟:循环创建数组
    JNIEXPORT void JNICALL Java_com_test_cy_JniTest_localReference
    (JNIEnv env, jobject jo){
    int i=0;
    for (; i < 5; i++){
    jclass cla = (
    env)->FindClass(env, "java/util/Date");
    jmethodID mid = (env)->GetMethodID(env, cla, "<init>", "()V");
    jobject obj = (
    env)->NewObject(env,cla,mid);

        printf("%x#\n", &obj);
        //不在使用这些对象
        //释放内存 通知垃圾回收器 回收对象
        (*env)->DeleteLocalRef(env, obj);
    }
    

    }

    //全局引用
    //多个方法里边可以去使用
    //共享 跨多个线程 手动控制内存的使用 可以手动释放
    jstring globalStr;

    //创建
    JNIEXPORT void JNICALL Java_com_test_cy_JniTest_createglobalReference
    (JNIEnv env, jobject jo){
    jstring str = (
    env)->NewStringUTF(env, "chengyue123");
    globalStr = (*env)->NewGlobalRef(env, str);
    }

    //获取
    JNIEXPORT jstring JNICALL Java_com_test_cy_JniTest_getglobalReference
    (JNIEnv *env, jobject jo){
    return globalStr;
    }
    //释放
    JNIEXPORT void JNICALL Java_com_test_cy_JniTest_deleteglobalReference
    (JNIEnv env, jobject jo){
    (
    env)->DeleteGlobalRef(env, globalStr);
    }

    //弱全局引用
    //在内存不足时释放所引用的对象,引用一个不常用的对象,如果为NULL 则重新创建弱引用。

    jstring globalwearRef;
    //创建
    JNIEXPORT void JNICALL Java_com_test_cy_JniTest_createglobalWeakReference
    (JNIEnv env, jobject jo){
    jstring str = (
    env)->NewStringUTF(env, "chengyue123");
    globalwearRef = (*env)->NewWeakGlobalRef(env, str);
    }

    //获取
    JNIEXPORT jstring JNICALL Java_com_test_cy_JniTest_getglobalWeakReference
    (JNIEnv *env, jobject jo){
    return globalwearRef;
    }
    //释放
    JNIEXPORT void JNICALL Java_com_test_cy_JniTest_deleteglobalWeakReference
    (JNIEnv env, jobject jo){
    (
    env)->DeleteWeakGlobalRef(env, globalwearRef);
    }

    //异常处理
    //1. 保证Java代码可以继续执行
    //2. 补救措施 保证后边 C /C++的代码可以继续执行

    //JNI 自己抛出的异常在Java 层无法被捕捉到,只能在C 层清空
    //用户通过ThrowNewke可以在java层显示

    JNIEXPORT void JNICALL Java_com_test_cy_JniTest_exception
    (JNIEnv env, jobject jo){
    jclass jla = (
    env)->GetObjectClass(env, jo);
    jfieldID jfid = (env)->GetFieldID(env, jla, "key2", "Ljava/lang/String;");
    //检测是否发生异常 后边java 代码继续执行
    jthrowable exception = (
    env)->ExceptionOccurred(env);
    if (exception!=NULL){
    //让java 代码继续执行
    (env)->ExceptionClear(env);
    //补救措施
    jfid = (
    env)->GetFieldID(env, jla, "key", "Ljava/lang/String;");
    }
    //获取属性的值
    jstring jstr = (env)->GetObjectField(env, jo, jfid);
    char str = (env)->GetStringUTFChars(env, jstr, NULL);
    //对比属性值是否合法
    if (_stricmp(str, "vc++") != 0){
    //抛出异常 给Java 处理
    jclass jlsa = (
    env)->FindClass(env, "java/lang/IllegalArgumentException");
    (*env)->ThrowNew(env, jlsa, "kay is invalid");
    }
    }

    相关文章

      网友评论

          本文标题:day07_JNI

          本文链接:https://www.haomeiwen.com/subject/slymtltx.html