JNI 学习笔记(一)-- jni函数调用流程,JNI理解和基本数据类型

版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
我的CSDN地址:http://blog.csdn.net/urrjdg
本文CSDN地址:http://blog.csdn.net/urrjdg/article/details/78153147
CSDN 和 简书 同步更新

看目录去CSDN

1.介绍 - JNI/NDK/静态库/动态库

1.JNI

java native interface
Java中定义的一种用于连接Java和C/C++接口的一种实现方式
使用环境:
java api 不能满足我们程序的需要的时候。
算法计算,图像渲染 效率要求非常高,
当需要访问一些已有的本地库

2.NDK

Native Development Kit
工具的集合。帮助开放者快速开放C/C++ 动态库的工具。
是Google在Android开发中提供的一套用于快速创建native工程的一个工具。使用这个工具可以很方便的编写,调试JNI的代码。

3.静态库和动态库

都是函数库。
静态库:.a (静态库在程序编译的时候就会直接连接到目标代码里面,所以在运行的时候就不需要了 )
动态库: .dll/.so (动态库在编译的时候不会自动连接到目标代码里面,就是说 这个动态库是独立吧,不会随着程序的编译直接链接进去,而是在程序运行的时候动态加载的,例如一下代码)

// 只有在运行工程的时候才会去走 这个static的代码块,这就是动态的过程     
static{
    System.loadLibrary("JNI_Native");
}

好处:功能独立,作为方案提供商不需要提供源码(保密)

4.JNIEnv 是什么?

C:
JNIEnv 结构体指针的别名
env 是二级指针

C++
JNIEnv 是结构体的别名
env 是一级指针

每个native 函数,都至少有两个参数(JNIEnv * , jclass/jobject)
jclass: native 静态方法
jobject: native 非静态方法

5. 数据类型

Jni基本数据类型

基本数据类型

引用类型

String jstring在·
Object jobject

引用类型

基本数据类型数组:

//type[] jTypeArray;
byte[] jByteArray;

引用类型数组

Object jobjectArray;

6. 属性签名

属性签名

例如:Java方法:

long f(int n,String s,int[] arr);

具有以下类型签名:

(ILjava/lang/String;[I)J

2. 使用jni 进行 java 调用 C 的 静态 和非静态navtive方法

1. 新建一个 Java工程


public class JniTest01 {

    // 静态方法
    public native static String getStringFromC();
    // 非静态方法
    public native String getStringFromC2();
    
    public static void main(String[] args) {
        System.out.println("Test01");
    }
    
}

2. 使用 javah 命令

使用 cmd 跳转到 JniTest01这个类 的当前 目录下 ,直接敲 javah ,生成 JniTest01.h 文件( 或者自己手写:java_类的全名_方法名)

/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class JniTest01 */

#ifndef _Included_JniTest01
#define _Included_JniTest01
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     JniTest01
 * Method:    getStringFromC
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_JniTest01_getStringFromC
  (JNIEnv *, jclass);

/*
 * Class:     JniTest01
 * Method:    getStringFromC2
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_JniTest01_getStringFromC2
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

3. 复制.h 头文件到cpp 工程 (Vistual Studio)

复制 .h 文件的 时候要先拷贝到 工程所在的头文件夹下面, 然后在 visual studio的工程那边 : 头文件右键 添加--》 现有项

4. 复制jni.h 和jni_md.h

同上

jni.hjni_md.h

C:\develop\Java\jdk1.8.0_111\include
C:\develop\Java\jdk1.8.0_111\include\win32

记得修改 JniMain.h#include <jni.h>#include "jni.h"

5. 实现.h 头文件中的声明函数

这是个C文件 不是Cpp,先用C进行演示,后面的系列会用到C++

#include "JniTest01.h"
#include "stdafx.h"
/*
* Class:     JniTest01
* Method:    getStringFromC
* Signature: ()Ljava/lang/String;
*/
// 静态方法 jclass
JNIEXPORT jstring JNICALL Java_JniTest01_getStringFromC
(JNIEnv * env, jclass jclz){
    return(*env)->NewStringUTF(env,"String frome C 01,ZekingLee");
}

/*
* Class:     JniTest01
* Method:    getStringFromC2
* Signature: ()Ljava/lang/String;
*/
// 非静态方法 jobject
JNIEXPORT jstring JNICALL Java_JniTest01_getStringFromC2
(JNIEnv * env, jobject jclz){
    return(*env)->NewStringUTF(env, "String frome C 02,ZekingLee");
}

6. 生成一个dll 动态库

右键 visual studio 的项目名 --》 属性 --》 配置属性 --》 常规 --》 配置类型 --》 动态库(.dll)

平台使用x64

如果出现 : 错误 1 error C1083: 无法打开预编译头文件: “x64\Debug\ConsoleApplication1.pch”: No such file or directory C:\Users\Zeking\Desktop\JNICode\Jni01\ConsoleApplication1\ConsoleApplication1\JniTest01.c 2 1 ConsoleApplication1

右键工程名字-->属性-->配置属性-->C/C++ -->预编译头--> 选择不适用预编译头

7. 在java中加载动态库

dll文件 复制到 java工程里面

8. 触发native函数


public class JniTest01 {

    // 静态方法
    public native static String getStringFromC();
    // 非静态方法
    public native String getStringFromC2();
    
    public static void main(String[] args) {
        System.out.println(getStringFromC());  // 输出  String frome C 01,ZekingLee
        
        JniTest01 jinTest01 = new JniTest01();
        System.out.println(jinTest01.getStringFromC2()); // 输出  String frome C 02,ZekingLee
         
    }
    
    static{
        System.loadLibrary("ConsoleApplication1");
    }
    
}

3. 使用jni 进行C 调用 java 的 静态 和非静态变量

遇到这个错误的解决方法:

error C4996: 'strcat': This function or variable may be unsafe. Consider using strcat_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. C:\Users\Zeking\Desktop\JNICode\Jni01\ConsoleApplication1\ConsoleApplication1\JniTest01.c 51 1 ConsoleApplication1

项目名右键--> 属性-->C/C++-->预处理器-->预处理定义 添加 _CRT_SECURE_NO_WARNINGS

public class JniTest02 {
    // 非静态变量
    public String key = "Key";
    // 静态变量
    public static int count = 99;
    // 调用非静态变量
    public native String accessField();
    // 调用静态变量
    public native void accessStaticField();
    
    static{
        System.loadLibrary("ConsoleApplication1");
    }
    
    public static void main(String[] args) {
        

        JniTest02 jniTest02 = new JniTest02();
        System.out.println(jniTest02.key);  // Key
        jniTest02.accessField();
        System.out.println(jniTest02.key);  // ZekingKey
        
        System.out.println(count);          // 99
        jniTest02.accessStaticField();
        System.out.println(count);          // 100
        
    }

}

#include "JniTest02.h"
#include "stdafx.h"
#include <string.h>
#include <stdio.h>

/*
* Class:     JniTest02
* Method:    accessField
* Signature: ()Ljava/lang/String;
* 
*/
// 访问非静态域 
JNIEXPORT jstring JNICALL Java_JniTest02_accessField
(JNIEnv * env, jobject jobj){
    // jclass
    jclass jclz = (*env)->GetObjectClass(env, jobj);

    // fieldId 属性名称,属性签名
    jfieldID fid = (*env)->GetFieldID(env, jclz, "key", "Ljava/lang/String;");
    // key -> dongNao key

    // 得到key 对应的值
    // GetXXXField
    jstring jstr = (*env)->GetObjectField(env, jobj, fid);

    // jni -> c
    char * c_str = (*env)->GetStringUTFChars(env, jstr, NULL);

    char text[30] = "Zeking";
    // 生成新的字符串 ZekingKey
    strcat(text, c_str);

    // C -> jni
    jstring new_str = (*env)->NewStringUTF(env, text);

    //setXXXField
    (*env)->SetObjectField(env, jobj, fid, new_str);

    (*env)->ReleaseStringChars(env, new_str, c_str);

    return new_str;
}

/*
* Class:     JniTest02
* Method:    accessStaticField
* Signature: ()V
*/
// 访问静态域
JNIEXPORT void JNICALL Java_JniTest02_accessStaticField
(JNIEnv * env, jobject jobj){

    jclass jclz = (*env)->GetObjectClass(env, jobj);

    jfieldID fid = (*env)->GetStaticFieldID(env, jclz, "count", "I");

    if (fid == NULL){
        printf("fid is Null");
    }

    jint count = (*env)->GetStaticIntField(env, jclz, fid);
    count++;

    (*env)->SetStaticIntField(env, jclz, fid, count);



}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容