JNI的基本使用一
Posted zhujm320
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JNI的基本使用一相关的知识,希望对你有一定的参考价值。
介绍
JNI即Java Native Interface的简称,java本地方法接口,通过JNI Java可以和C相互调用。Java语言也是通过JNI接口来调用系统的功能,只不过JNI的实现部分在JDK中,这样可以增加Java的功能。同样用户程序也可以通过实现JNI接口来调用本地方法。如: 如: windows和linux上Java程序需要调用外设驱动,就需要使用JNI;android上NDK也是通过JNI进行调用。本文主要讲解在windows上java通过jni调用本地方法,测试效果和在android上通过java调用so一样(JNI的规则一致的),为了方便点采用windows来实践。
准备工作:
-
vs2015
-
IntelliJ
本次通过vs2015编写dll,然后通过java进行调用。
数据类型
基本数据类型
Java类型 | JNI类型 | 说明 |
---|---|---|
boolean | jboolean | typedef unsigned char jboolean; |
byte | jbyte | typedef signed char jbyte; |
char | jchar | typedef unsigned short jchar; |
short | jshort | typedef short jshort; |
int | jint | typedef long jint; |
long | jlong | typedef __int64 jlong; |
float | jfloat | typedef float jfloat; |
double | jdouble | typedef double jdouble; |
void | void | void |
从上可以看出jni中的基本类型,都是由其他类型定义而来
引用类型
-
jobject
-
jclass (java.lang.Class objects)
-
jstring (java.lang.String objects)
-
jarray (arrays)
-
jobjectArray (object arrays)
-
jbooleanArray (boolean arrays)
-
jbyteArray (byte arrays)
-
jcharArray (char arrays)
-
jshortArray (short arrays)
-
jintArray (int arrays)
-
jlongArray (long arrays)
-
jfloatArray (float arrays)
-
jdoubleArray (double arrays)
-
-
jthrowable (java.lang.Throwable objects)
-
签名
签名 | Java类型 |
---|---|
Z | boolean |
B | byte |
C | char |
S | short |
I | int |
J | long |
F | float |
D | double |
L fully-class; | fully-class |
[type | type[] |
例子:
void test(int arg1, byte arg2, char arg3, String []arg4);
方法签名: (IBC[Ljava/lang/String;)V
类属性映射
Java | Jni |
---|---|
Method | jmethodID |
Field | jfieldID |
Java调用JNI准备
-
需要调用使用jni的java文件需要静态加载动态库
static {
System.loadLibrary("JNIDll");
}
2.声明native方法,native方法与c层实现的代码一一对映
public native void javaCallNative();
public native void javaCallNative1(int arg);
public native void javaCallNative2(long arg);
public native void javaCallNative3(float arg);
public native void javaCallNative4(byte[] arg);
public native void javaCallNative5(String arg);
/**
* 通过该接口c层回调java接口
*/
public native void nativeCallJavaTest();
Java测试代码如下:
package com.stx.jni;
import java.io.File;
public class JNITest {
static {
System.loadLibrary("JNIDll");
}
public static void main(String[] args) {
System.out.println("==================");
File file = new File("");
System.out.println("curDir " + file.getAbsolutePath());
JNITest jniTest = new JNITest();
jniTest.javaCallNative();
jniTest.javaCallNative1(1);
jniTest.javaCallNative2(2);
jniTest.javaCallNative3(3.0f);
byte[] byteTest = new byte[]{1, 2, 3, 4, 5, 6};
jniTest.javaCallNative4(byteTest);
String strTest = "Hello World";
jniTest.javaCallNative5(strTest);
jniTest.nativeCallJavaTest();
}
public native void javaCallNative();
public native void javaCallNative1(int arg);
public native void javaCallNative2(long arg);
public native void javaCallNative3(float arg);
public native void javaCallNative4(byte[] arg);
public native void javaCallNative5(String arg);
/**
* 通过该接口c层回调java接口
*/
public native void nativeCallJavaTest();
/**
* 提供给JNI调用
* @param arg1
* @param arg2
* @param arg3
*/
public void test(int arg1, byte[] arg2, String arg3){
System.out.println("this is java test print...");
System.out.println("arg1: " + arg1);
System.out.println("================arg2 begin=============");
for (byte b : arg2){
System.out.println(""+b);
}
System.out.println("================arg2 end=============");
System.out.println("arg3: " + arg3);
}
}
C代码
工程准备
-
新建一个vs2015工程,选择dll
文件->新建项目
点击确定,然后点击下一步,选择建dll工程
-
点击完成,工程就建好了。
-
将jni.h和jni_md.h拷贝到工程目录中
C:\\Program Files\\Java\\jdk1.8.0_231\\include\\jni.h
C:\\Program Files\\Java\\jdk1.8.0_231\\include\\win32\\jni_md.h
并将其添加到工程中
-
新建jni实现文件 JNIDll.h和JNIDll.cpp
本次实现为静态注册的方式,对静态注册说明一下, jni中的函数如何和java中的函数进行绑定
通用格式如下, 如果包名为a.b.c, java文件名为d, 函数名为f,那么jni中的对应的函数名为:Java_a_b_c_d_f
以测试工程包为例:
java jni javaCallNative
Java_com_stx_jni_JNITest_javaCallNative
-
代码如下:
头文件
#pragma once #include "jni.h" #ifndef _Included_JNIDLL #define _Included_JNIDLL #ifdef __cplusplus extern "C" { #endif JNIEXPORT void JNICALL Java_com_stx_jni_JNITest_javaCallNative (JNIEnv *, jobject); JNIEXPORT int JNICALL Java_com_stx_jni_JNITest_javaCallNative1 (JNIEnv *, jobject, jint); JNIEXPORT int JNICALL Java_com_stx_jni_JNITest_javaCallNative2 (JNIEnv *, jobject, jlong); JNIEXPORT int JNICALL Java_com_stx_jni_JNITest_javaCallNative3 (JNIEnv *, jobject, jfloat); JNIEXPORT int JNICALL Java_com_stx_jni_JNITest_javaCallNative4 (JNIEnv *, jobject, jbyteArray); JNIEXPORT int JNICALL Java_com_stx_jni_JNITest_javaCallNative5 (JNIEnv *, jobject, jstring); JNIEXPORT void JNICALL Java_com_stx_jni_JNITest_nativeCallJavaTest (JNIEnv *, jobject); char* jstringtochar(JNIEnv *env, jstring jsStr); jstring chartojstring(JNIEnv* env, char* csStr); #ifdef __cplusplus } #endif #endif
c定义// JNIDll.cpp : 定义 DLL 应用程序的导出函数。 // #include <stdio.h> #include <stdlib.h> #include <string.h> #include "jni.h" #include "JNIDll.h" JNIEXPORT void JNICALL Java_com_stx_jni_JNITest_javaCallNative (JNIEnv * env, jobject jObj) { printf("Java_com_stx_jni_JNITest_javaCallNative---->\\n"); } JNIEXPORT int JNICALL Java_com_stx_jni_JNITest_javaCallNative1 (JNIEnv * env, jobject jObj, jint arg) { printf("Java_com_stx_jni_JNITest_javaCallNative1---->, arg: %d\\n", arg); return 0; } JNIEXPORT int JNICALL Java_com_stx_jni_JNITest_javaCallNative2 (JNIEnv *env, jobject jObj, jlong arg) { printf("Java_com_stx_jni_JNITest_javaCallNative2---->, arg: %d\\n", arg); return 0; } JNIEXPORT int JNICALL Java_com_stx_jni_JNITest_javaCallNative3 (JNIEnv *env, jobject jObj, jfloat arg){ printf("Java_com_stx_jni_JNITest_javaCallNativ3---->, arg: %f\\n", arg); return 0; } JNIEXPORT int JNICALL Java_com_stx_jni_JNITest_javaCallNative4 (JNIEnv *env, jobject jObj, jbyteArray arg) { printf("Java_com_stx_jni_JNITest_javaCallNative4---->\\n"); int len = env->GetArrayLength(arg); jbyte * pArray = env->GetByteArrayElements(arg, JNI_FALSE); for (int i = 0; i < len; i++) { printf("%d\\n", pArray[i]); } env->ReleaseByteArrayElements(arg, pArray, JNI_FALSE); return 0; } JNIEXPORT int JNICALL Java_com_stx_jni_JNITest_javaCallNative5 (JNIEnv *env, jobject jObj, jstring arg) { printf("Java_com_stx_jni_JNITest_javaCallNative5---->\\n"); const char* csArgs = env->GetStringUTFChars(arg, false); printf("csArgs: %s\\n", csArgs); env->ReleaseStringUTFChars(arg, csArgs); return 0; } JNIEXPORT void JNICALL Java_com_stx_jni_JNITest_nativeCallJavaTest (JNIEnv *env, jobject jObj) { printf("Java_com_stx_jni_JNITest_nativeCallJavaTest---->\\n"); jclass clazz = env->FindClass("com/stx/jni/JNITest"); if (clazz == NULL) clazz = env->GetObjectClass(jObj); if (clazz != NULL) { jmethodID method = env->GetMethodID(clazz, "test", "(I[BLjava/lang/String;)V"); if(method != NULL){ int arg1 = 10; jbyte* pByte = new jbyte[6]; for (int i = 0; i < 6; i++) { pByte[i] = i; } jbyteArray arg2 = env->NewByteArray(6); env->SetByteArrayRegion(arg2, 0, 6, pByte); char* pCsStr = "C++ Char"; jstring arg3 = chartojstring(env, pCsStr); env->CallVoidMethod(jObj, method, arg1, arg2, arg3); } else { printf("find method test faild..."); } } else { printf("find class faild..."); } } char* jstringtochar(JNIEnv *env, jstring jsStr) { char* rtn = NULL; jclass clsstring = env->FindClass("java/lang/String"); jstring strencode = env->NewStringUTF("utf-8"); jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B"); jbyteArray barr = (jbyteArray)env->CallObjectMethod(jsStr, mid, strencode); jsize alen = env->GetArrayLength(barr); jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE); if (alen > 0){ rtn = (char*)malloc(alen + 1); memcpy(rtn, ba, alen); rtn[alen] = 0; } env->ReleaseByteArrayElements(barr, ba, 0); return rtn; } jstring chartojstring(JNIEnv* env, char* csStr) { jclass strClass = env->FindClass("Ljava/lang/String;"); jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V"); jbyteArray bytes = env->NewByteArray(strlen(csStr)); env->SetByteArrayRegion(bytes, 0, strlen(csStr), (jbyte*)csStr); jstring encoding = env->NewStringUTF("utf-8"); return (jstring)env->NewObject(strClass, ctorID, bytes, encoding); }
以上代码都可以编译运行通过。
以上是关于JNI的基本使用一的主要内容,如果未能解决你的问题,请参考以下文章