JAVA通过JNI调用C++

JAVA通过JNI调用C++,第1张

JAVA通过JNI调用C++ 0.前置条件与JNI预备知识

需要gcc编译器

字符javac++/c
Vvoidvoid
Zjbooleanboolean
Ijintint
Jjlonglong
Djdoubledouble
Fjfloatfloat
Bjbytebyte
Cjcharchar
Sjshortshort
[IjintArray[]int[]
[FjfloatArray[]float[]
[BjbyteArraybyte[]
[CjcharArraychar[]
[SjshortArrayshort[]
[DjdoubleArraydouble[]
[JjloneArraylong[]
[ZjbooleanArrayboolean[]
Ljava/lang/Stringjstring
其他对象类推
(Ljava/lang/String;I)Ljava/lang/String;  <===>  String helloJNI(String a,int b)
(II)V <===> void helloJNI(int a,int b)
1.创建Java项目 代码如下
public class JNITest {

    public native String helloJNI(String name,int age);

    public static void main(String[] args) {
        JNITest jniTest = new JNITest();
        String z3 = jniTest.helloJNI("z3", 18);
        System.out.println(z3);
    }
}

关于上述代码解释如下:native表示该函数的实现不是用java实现的,可能是C/C++等语言实现,

2.编写C++实现 2.1 创建JNI.cpp文件
// “jni.h” 由先从当前目录去找jni.h
#include "jni.h"

jstring cppJNI(JNIEnv* env, jobject clazz, jstring name, jint age) {
	const char* chars = "hello java";
	const jstring result = env->NewStringUTF(chars);
	const char* nameChar = env->GetStringUTFChars(name, NULL);
	return result;
}

/*
	JVM启动时 会优先查看动态链接库中是否有JNI_OnLoad()函数
*/
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
	JNIEnv* env;
	if (JNI_OK != vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_8)) {
		printf("JNI_OnLoad cloud not get jni env");
		return JNI_ERR;
	}
	jclass clazz = env->FindClass("com/huf/JNITest");

	//通过 JNINativeMethod映射 c++函数与java函数直接的关系,从而不用在C++ 提供的JNI函数时的函数名不需要按照一定规则才能访问
	JNINativeMethod methods[] = {
		{"helloJNI","(Ljava/lang/String;I)Ljava/lang/String;",(void*)cppJNI},
	};

	if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof((methods)[0])) < 0) {
		return JNI_ERR;
	}
	return JNI_VERSION_1_8;
}
2.2 将jdk环境下的 jni.h与jni_md.h复制到出来

<你的目录>\jdk8u322-b06\include\jni.h

<你的目录>\jdk8u322-b06\include\win32\jni_md.h

2.3 生成动态链接库

此步骤需要gcc编译器没有请自行安装

windowslinuxmac
dllsojnilib
gcc -shared -o JNITest.dll .\JNI.cpp

执行成功会看见JNITest.dll文件

2.4 修改java代码
public class JNITest {

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

    public native String helloJNI(String name,int age);

    public static void main(String[] args) {
        JNITest jniTest = new JNITest();
        String z3 = jniTest.helloJNI("z3", 18);
        System.out.println(z3);
    }
}

2.5 执行java main函数测试

不出意外会出现如下错误:

no JNITest in java.library.path

因为它默认会去默认的路径找这个JNITest.dll库,所以我们需要手动指定

-Djava.library.path=E:\idea\jni\src\com\huf\

2.6 再次执行
hello java
2.7 C++回调java
  • c++代码如下
// pch.cpp: 与预编译标头对应的源文件
#include "jni.h"

JNIEnv* m_ENV = NULL;
JavaVM* m_JVM = NULL;
jobject object = NULL;

void callJava(const char* chars, int age) {
	bool flag = false;
	if (m_JVM->AttachCurrentThread((void**)&m_ENV, NULL) != JNI_OK) {
		fprintf(stderr, "AttachCurrentThread error\n");
		return;
	}
	flag = true;
	jclass clazz = m_ENV->GetObjectClass(object);
	//jclass clazz = m_env->FindClass("com/huf/JNITest");
	if (clazz == NULL) {
		fprintf(stderr, "GetObjectClass error\n");
		if (flag) {
			m_JVM->DetachCurrentThread();
		}
		return;
	}
	jmethodID method = m_ENV->GetMethodID(clazz, "callBack", "(Ljava/lang/String;I)V");
	if (NULL == method) {
		if (flag) {
			m_JVM->DetachCurrentThread();
		}
		fprintf(stderr, "GetMethodID error\n");
		return;
	}
	jobject object = m_ENV->AllocObject(clazz);
	jstring re = m_ENV->NewStringUTF(chars);
	m_ENV->CallVoidMethod(object, method, re, age);
	if (flag) {
		m_JVM->DetachCurrentThread();
	}
}

jstring cppJNI(JNIEnv* env, jobject clazz, jstring name, jint age) {
	const char* chars = "hello java";
	const jstring result = env->NewStringUTF(chars);
	const char* nameChar = env->GetStringUTFChars(name, NULL);
	object = clazz;
	callJava(nameChar, age);
	return result;
}

/*
	JVM启动时 会优先查看动态链接库中是否有JNI_OnLoad()函数
*/
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
	JNIEnv* env;
	if (JNI_OK != vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_8)) {
		printf("JNI_OnLoad cloud not get jni env");
		return JNI_ERR;
	}
	m_ENV = env;
	m_JVM = vm;
	jclass clazz = env->FindClass("com/huf/JNITest");

	//通过 JNINativeMethod映射 c++函数与java函数直接的关系,从而不用在C++ 提供的JNI函数时的函数名不需要按照一定规则才能访问
	JNINativeMethod methods[] = {
		{"helloJNI","(Ljava/lang/String;I)Ljava/lang/String;",(void*)cppJNI},
	};

	if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof((methods)[0])) < 0) {
		return JNI_ERR;
	}
	return JNI_VERSION_1_8;
}
  • java代码如下:
public class JNITest {

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

    public native String helloJNI(String name,int age);

    public void callBack(String name, int age) {
        System.out.println("c++ ======> java");
        System.out.printf("name : %s \n age : %d \n", name, age);
    }

    public static void main(String[] args) {
        JNITest jniTest = new JNITest();
        String z3 = jniTest.helloJNI("z3", 18);
        System.out.println(z3);
    }
}

最后

可以将无用文件删除只留下如图

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/785902.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-04
下一篇 2022-05-04

发表评论

登录后才能评论

评论列表(0条)

保存