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

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

网友评论

      本文标题:day07_JNI

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