jni的基本使用一(代码片段)

zhujm320 zhujm320     2022-12-08     361

关键词:

介绍

       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来实践。

准备工作:

  1. vs2015

  2. IntelliJ

    本次通过vs2015编写dll,然后通过java进行调用。

数据类型

基本数据类型

Java类型JNI类型说明
booleanjbooleantypedef unsigned char jboolean;
bytejbytetypedef signed char jbyte;
charjchartypedef unsigned short jchar;
shortjshorttypedef short jshort;
intjinttypedef long jint;
longjlongtypedef __int64 jlong;
floatjfloattypedef float jfloat;
doublejdoubletypedef double jdouble;
voidvoidvoid

从上可以看出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类型
Zboolean
Bbyte
Cchar
Sshort
Iint
Jlong
Ffloat
Ddouble
L fully-class;  fully-class
[typetype[]

例子:

void test(int arg1, byte arg2, char arg3, String []arg4);

方法签名: (IBC[Ljava/lang/String;)V

类属性映射

JavaJni
MethodjmethodID
FieldjfieldID

Java调用JNI准备

  1. 需要调用使用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代码

工程准备

  1. 新建一个vs2015工程,选择dll

    文件->新建项目

点击确定,然后点击下一步,选择建dll工程

  1. 点击完成,工程就建好了。

  2. 将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

    并将其添加到工程中

  3. 新建jni实现文件 JNIDll.h和JNIDll.cpp

    本次实现为静态注册的方式,对静态注册说明一下, jni中的函数如何和java中的函数进行绑定
    通用格式如下, 如果包名为a.b.c, java文件名为d, 函数名为f,那么jni中的对应的函数名为:Java_a_b_c_d_f
    以测试工程包为例:
     

    javajni
    javaCallNative
    Java_com_stx_jni_JNITest_javaCallNative

     
  4. 代码如下:

    头文件

    #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);
    
    
    


    以上代码都可以编译运行通过。

         win32源码下载

 

 

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语言如... 查看详情