关键词:
介绍
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基本使用二(代码片段)
...在JNI中如何开线程。JNI的基础部分,请详细参考JNI的基本使用一动态注册 与静态注册相比,有如下优缺点: 优点: 1.native中函数名简洁,方便记忆 2. 需要使用时,需要在JNI_OnLoad()进行注册 缺点: ... 查看详情
jni基本使用二(代码片段)
...在JNI中如何开线程。JNI的基础部分,请详细参考JNI的基本使用一动态注册 与静态注册相比,有如下优缺点: 优点: 1.native中函数名简洁,方便记忆 2. 需要使用时,需要在JNI_OnLoad()进行注册 缺点: ... 查看详情
ndk:jni的数据结构(代码片段)
文章目录一、概述二、Native的数据类型2.1基本类型2.2引用类型2.3jclass与jobject的使用场景三、属性ID和方法ID四、方法签名(Signatures)五、JNINativeMethod六、全局JNINativeMethod的注册流程六、JavaVM指针七、JNIEnv指针八、小结一... 查看详情
androidjni详解(代码片段)
...一、前言: 本篇文章是针对android开发过程中的使用的jni技术做一些的原理上的解析,不再介绍具体的jni的使用,关于如何在android中使用jni开发的教程可以去网上搜索然后自行尝试。本篇文章主要介绍的比如jni... 查看详情
androidjni开发四:鸿蒙jni开发(代码片段)
...础知识AndroidJNI开发二:如何生成SO库AndroidJNI开发三:SO库的使用AndroidJNI开发四:鸿蒙JNI开发一、JNI1.1创建工程用DevEcoStudio创建一个新的工程,我的DevEcoStudio版本为2.1。创建工程第一步的时候,... 查看详情
你应该了解的jni知识——java与jni互相调用(代码片段)
...识(一)——静态注册与动态注册中,了解了JNI是如何使用的,以及两种注册方式的使用以及区别。本篇博客将介绍Java和JNI的互相调用,因此主要包括两部分:JNI层调用Java层Java层调用JNI、Native层JNI层调用Java层JNI层... 查看详情
鸿蒙jni开发(代码片段)
...供了JNI开发的环境,我们在这个模版里可以更容易的使用JNI去调用C语言代码。(1)创建工程第一步:选择NativeC 查看详情
jni使用方法(代码片段)
...在java代码中调用本地库的功能。下面记录一下JNI简单的使用方法创建java端接口1publicclassJNIIterface23//导入最终生成的dll文件4static5System.loadLibrary("JNIDemo");678//声明dll文件中实现的接口9publicnativeintMyMethod();1011publicnativeintadd(in 查看详情
将so|jni|ndk之间的关系说明白(代码片段)
...那么,Android系统为什么要使用.so文件呢?Android系统应用基本都是基于Java语言开发,而Java语言是不能直接访问Android系统底层的硬件接口。而Android系统中可以通过JNI和硬件访问服务去访问系统底层的硬件接口。比如:开启蓝牙、... 查看详情
你应该了解的jni知识——静态注册与动态注册(代码片段)
最近一直在做native这边的跨平台开发,整个结构基本就是下图:大体说来就是,底层C/C++代码。那么对于两端分别有不同的处理:对于Android端而言,由于需要给Java端使用,因此需要提供JNI接口,... 查看详情
jni两种注册过程实战(代码片段)
...比较二者的优劣和实战中的一些坑0x00静态注册静态注册基本原理根据函数名来建立java方法和JNI函数间的一一对应关系。静态有两个非常重要的关键字JNIEXPORT和JNICALL,这两个关键字时宏定义,主要用于说明该函数是JNI函... 查看详情
[rk3568][android11]jni调用流程分析(代码片段)
...二、JNI一般应用场景三、什么是NDK?四、流程五、android源代码开发实现JNI具体操作一、JNI是什么?JNI是JavaNativeInterface的缩写,即Java本地接口。从Java1.1开始,JNI标准成为Java平台的一部分,它允许java代码和用其它语言编写的代码进... 查看详情
[rk3568][android11]jni调用流程分析(代码片段)
...二、JNI一般应用场景三、什么是NDK?四、流程五、android源代码开发实现JNI具体操作一、JNI是什么?JNI是JavaNativeInterface的缩写,即Java本地接口。从Java1.1开始,JNI标准成为Java平台的一部分,它允许java代码和用其它语言编写的代码进... 查看详情
androidjni开发一:jni基础知识(代码片段)
JNI基础知识Android系统底层的框架大多采用的是C或者C++语言实现的,但是Android上层的框架是采用Java实现的,所以我们平常进行Android也是采用Java语言开发。虽然Android底层采用C或者C++实现,但是我们在进行... 查看详情
androidjni开发一:jni基础知识(代码片段)
JNI基础知识Android系统底层的框架大多采用的是C或者C++语言实现的,但是Android上层的框架是采用Java实现的,所以我们平常进行Android也是采用Java语言开发。虽然Android底层采用C或者C++实现,但是我们在进行... 查看详情
混合编程jni第四篇之引用和异常(代码片段)
继续写JNI的知识点上篇基本上介绍了数据的转换以及方法签名的相关知识点,不懂的可以看看之前的文章建议循序渐进,不可冒进今天继续介绍JNI的知识点 除八种基本数据类型之外的都是引用数据类型;关于引用Java虚拟... 查看详情
混合编程jni第七篇之jni的命令行们(代码片段)
... 今天将继续JNI的学习,jni编程中常使用的一些命令行工具如何使用事半功倍,今天就快速的过一下,希望在接下来的使用中可以发挥效果 javahjavah是Java提供的生成jni头 查看详情
jni详解(代码片段)
...java文件名”)调用,此方法没有用到JNI.(了解) JNI_C语言的基本类型回顾java的8大基本类型:byte:占用1个字节short:占用2个字节int:占用4个字节char:占用2个字节float:占用4个字节double:占用8个字节boolean:占用1个字节long:占用8个字节C语言如... 查看详情