博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JNI_1
阅读量:6392 次
发布时间:2019-06-23

本文共 12314 字,大约阅读时间需要 41 分钟。

什么是JNI

JNI(Java Native Interface) java本地开发接口 

JNI 是一个协议, 有了这个协议可以使Java代码和C/C++代码相互调用.

为什么用JNI

1、扩展JVM功能,访问驱动,操作硬件(物联网、智能家居、 

车载电脑) 
2
、效率上c/c++语言效率更高数学运算,实时渲染的游戏上, 
视频处理 
3
java反编译比c语言容易, 通过JNI增强代码安全性(加密算法放到C实现)

4、代码移植,复用已经存在的c代码(opencv,ffmpeg…

怎么用JNI

1.C/C++语言 

2.掌握java jni流程 
3.NDK (native develop kits )

开发环境介绍

windows下用轻量级 dev-c++

C语言基本数据类型

Java 八大基本数据类型 C基本数据类型

boolean 

byte 
char char 
int int 
float float 
double double 
long long 
short short 
C没有boolean byte 
signed unsigned
有符号无符号修饰符只能修饰整形变量 
signed
有符号最高位符号位可以表示负数 
unsigned
无符号最高位仍然是数值位不可以表示负数

输入输出函数

输出函数 

printf(“要输出的内容+占位符”,…….) 
常用占位符 
%d - int 
%ld – long int 
%lld - long long 
%hd –
短整型 
%c - char 
%f - float 
%lf – double 
%u –
无符号数 
%x –
十六进制输出 int 或者long int 或者short int 
%o -
八进制输出 
%s –
字符串

输入函数 Scanf 

Int len; Scanf(“%d”,&len); &取地址符号

 

 

什么是指针

int main(void){    int * p; //p 是变量的名字, int * 是一个类型    //这个变量存放的是int类型变量的地址。    int i =3;    p=&i;    system(“pause”);      return 0;}

 

指针常见错误

指针变量声明后未赋值直接用

声明的指针类型和指向的类型要一致

指针和指针变量的关系

指针就是地址,地址就是指针 

地址就是内存单元的编号 
指针变量是存放地址的变量 
指针和指针变量是两个不同的概念 
但是要注意:通常我们叙述时会把指针变量简称为指针,实际它们含义并不一样

为什么使用指针

直接访问硬件 (opengl 显卡绘图

快速传递数据(指针表示地址
返回一个以上的值(返回一个数组或者结构体的指针
表示复杂的数据结构(结构体
方便处理字符串

*号的三种含义

*号的含义 

数学运算符: 3 * 5 
定义指针变量: int * p 
指针运算符(取值): *p (p的内容(地址)在内存中的值)

指针练习互换两个数字

swap(int* i, int* j) { // 引用传递     int temp = *i;       *i = *j;       *j = temp; }main()        int i = 89;       int j = 10;      swap(&i, &j);      printf("i=%d\n", i);       printf("j=%d\n", j);      system("pause");}

 

指针练习函数返回一个以上的值

change(int* a, int* b) {    *a = 1;    *b = 2;}main() {    int a = 3, b = 5;    change(&a, &b);    printf(“a=%d, b=%d\n”, a, b);    system(“pause”);}

 

指针和数组的关系

数组名 

int a[5]; // a是数组名,5是数组的大小,元素个数 
数组名称是个指针常量,它存放的是数组中第一个元素的地址 
int a[5]; 
&a[0]
等价于 &a 
下标和指针的关系 
int a[5]; 
a[i]
等价于 *(a + i) // 这里i的范围是0~4(数组长度 -1)

指针的长度

不管什么类型的指针都是4个字节.(64位系统8字节

C语言为了方便指针运算, 定义各种基本类型的指针, 每种类型的指针运算时所偏移量的值是根据类型的长度决定的.

多级指针

int i = 10; int* p1 = &i; // 一级指针 int** p2 = &p1; // 二级指针 int*** p3 = &p2; // 三级指针 int**** p4 = &p3; // 四级指针 ****p4 = 99; // 修改变量i的值为99;

 

主函数获取子函数变量地址

void function(int** p){     int i = 4;     *p = &i;     printf("子函数打印i的地址为%#x\n", &i);    }main(){       int* mainp;       function(&mainp);             printf("主函数打印i的地址为%#x\n", mainp);           printf("i的值为%d\n", *mainp);       system("pause");}

 

静态内存和动态内存

静态内存是系统是程序编译执行后系统自动分配,由系统自动释放, 静态内存是栈分配的

动态内存是开发者手动分配的, 是堆分配的
栈内存 
*
系统自动分配 
*
系统自动销毁 
*
连续的内存区域 
*
向低地址扩展 
*
大小固定 
*
栈上分配的内存称为静态内存 
堆内存 
*
程序员手动分配 
* java
new * cmalloc 
*
空间不连续 
*
大小取决于系统的虚拟内存 
* C
:程序员手动回收free 
* java
:自动回收 
*
堆上分配的内存称为动态内存

申请堆内存

malloc(memory allocate) 函数 

malloc 申请一块堆内存

free(地址); 回收内存 

回收malloc 申请的堆内存

realloc re- allocate 

重新申请一块堆内存

结构体

struct Student {    int age;    float score;    char sex;}; main() {    struct Student stu = {
18, 88.5, 'M'};}

 

使用结构体变量

struct Student stu = {
80,55.5,'F'};struct Student stu2;stu2.age = 10;stu2.score = 88.8f;stu2.sex= ‘M';printf("%d %f %c\n", st.age, st.score, st.sex); // 结构体指针struct Student * pStu;pStu = &stu;pStu->age 在计算机内部会被转换为 (* pStu).age

 

 

pStu ->age的含义: pStu所指向的结构体变量中的age这个成员

函数的指针

1.定义int (*pf)(int x, int y); 

2.赋值 pf = add; 
3.
引用 pf(3,5); 
4.
结构体中不能定义函数,只能声明函数指针

Union 联合体

struct Date {      int year;      int month;     int day;};union Mix {     long i;     int k;     char ii;};main() {       printf("date:%d\n",sizeof(struct Date));       printf("mix:%d\n",sizeof(union Mix));       system("pause");}

 

枚举

enum WeekDay {     Monday=0,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday}; main() {       enum WeekDay day = Sunday;       printf("%d\n",day);       system("pause");}

 

typedef

声明自定义数据类型,配合各种原有数据类型来达到简化编程的目的的类型定义关键字。

#include 
#include
typedef int i;typedef long l;main() { i m = 10; l n = 123123123; printf("%d\n", m); printf("%ld\n", n); system("pause"); }

 

JNI 协议

 

NDK HelloWorld

1.创建一个android工程 

2.java代码中写声明native方法 
3.
创建jni目录,编写c代码,方法名字要对应 
4.
编写Android.mk文件 
5.NDK
编译生成动态链接库 
6.java
代码load动态库.调用native代码

javah 生成头文件

注意: 不同版本的JDK操作方式不同.

命令: javah <包名+类名>

JDK1.6使用方式 

在工程的bin/classes目录下, 执行javah命令
JDK1.7
使用方式 
在工程的src目录下, 执行javah命令.

NDK 简便开发流程

1.     关联NDK: Window -> Preferences -> Android -> NDK

2.     创建Android工程, 声明native方法.

3.     设置函数库名字: 右键工程 -> Android Tools -> App Native support

4.     使用javah生成.h的头文件, 并把.h文件拷贝到工程下jni文件夹中.

5.     c代码提示: 右键工程 -> Properties -> C/C++ General -> Path and Symbols // Includes -> Add -> File system 选中以下路径.latforms\android-18\arch-arm\usr\include

6.     把后缀名.cpp改成.c, 实现native方法.

7.     java代码中加载动态库, 调用native方法.

java c之间的数据传递

public native int add(int x, int y); 

public native String sayHelloInC(String s); 
public native int[] arrElementsIncrease(int[] intArray);

c代码中使用logcat

Android.mk文件增加以下内容

LOCAL_LDLIBS += -llog

C代码中增加以下内容

#include 

 

C语言调用java方法

C调用java空方法 

public void helloFromJava(){ 
C调用java中的带两个int参数的方法 
public int add(int x,int y) { 
C
调用java中参数为string的方法 
public void printString(String s){ 
}

JNI 方法签名

签名类型 Java类型 

Z boolean 
B byte 
C char 
S short 
I int 
J long 
F float 
D double 
L全类名; 引用类型 
[
类型数组

C语言回调java静态方法

C语言调用下面静态方法.

    

public static void sayHello(String text) {        System.out.println("MainActivity:showText: " + text);    }

 

 

C语言回调java刷新界面

C语言调用下面Activity中方法, 弹出吐司.

public void showToast(String text) {        Toast.makeText(this, text, 0).show();    }

 

 

eclipse找不到ndk选项解决办法

NDK插件 com.android.ide.eclipse.ndk_23.0.2.1259578.jar 如果在eclipse里配置ndk却发现没有配置的选项,则需要此插件,放置在eclipse/plugins下,重启即可。

AM命令

am命令 :adb shell里可以通过am命令进行一些操作如启动activity Service 启动浏览器等等 

am命令的源码在Am.java, adb shell里执行am命令实际上就是启动一个线程执Am.javamain方法,am命令后面带的参数都会当作运行时的参数传递到main函数中 
am
命令可以用start子命令,并且带指定的参数 
常见参数: -a: action -d data -t 表示传入的类型 -n 指定的组件名字 
举例: adb shell中通过am命令打开网页 
am start –user 0 -a android.intent.action.VIEW -d 
 
通过am命令打开activity 
am start –user 0 -n com.ngyb.cpphello/com.ngyb.cpphello.MainActivity

execlp

execlp c语言中执行系统命令的函数 

execlp() 会从PATH环境变量所指的目录中查找符合参数file的文件找到后就执行该文件, 第二个参数开始就是执行这个文件的 args[0],args[1] 最后一个参数用(char*)NULL结束 
android
开发中 execlp函数对应androidpath路径为 
system/bin/
目录 
调用格式 
execlp(“am”, “am”, “start”, “–user”,”0”,”-a”, “android.intent.action.VIEW”, “-d”, “
“, (char *) NULL);

execlp(“am”, “am”, “start”, “–user”,”0”, “-n” , “com.ngyb.cforktest/com.ngyb.cforktest.MainActivity”,(char *) NULL);

 

 

什么是JNI

JNI(Java Native Interface) java本地开发接口 

JNI 是一个协议, 有了这个协议可以使Java代码和C/C++代码相互调用.

为什么用JNI

1、扩展JVM功能,访问驱动,操作硬件(物联网、智能家居、 

车载电脑) 
2
、效率上c/c++语言效率更高数学运算,实时渲染的游戏上, 
视频处理 
3
java反编译比c语言容易, 通过JNI增强代码安全性(加密算法放到C实现)

4、代码移植,复用已经存在的c代码(opencv,ffmpeg…

怎么用JNI

1.C/C++语言 

2.掌握java jni流程 
3.NDK (native develop kits )

开发环境介绍

windows下用轻量级 dev-c++

C语言基本数据类型

Java 八大基本数据类型 C基本数据类型

boolean 

byte 
char char 
int int 
float float 
double double 
long long 
short short 
C没有boolean byte 
signed unsigned
有符号无符号修饰符只能修饰整形变量 
signed
有符号最高位符号位可以表示负数 
unsigned
无符号最高位仍然是数值位不可以表示负数

输入输出函数

输出函数 

printf(“要输出的内容+占位符”,…….) 
常用占位符 
%d - int 
%ld – long int 
%lld - long long 
%hd –
短整型 
%c - char 
%f - float 
%lf – double 
%u –
无符号数 
%x –
十六进制输出 int 或者long int 或者short int 
%o -
八进制输出 
%s –
字符串

输入函数 Scanf 

Int len; 
Scanf(“%d”,&len); &取地址符号

什么是指针

int main(void)

{

    int * p; //p 是变量的名字, int * 是一个类型

    //这个变量存放的是int类型变量的地址。

    int i =3;

    p=&i;

    system(“pause”);

      return 0;

}

指针常见错误

指针变量声明后未赋值直接用

声明的指针类型和指向的类型要一致

指针和指针变量的关系

指针就是地址,地址就是指针 

地址就是内存单元的编号 
指针变量是存放地址的变量 
指针和指针变量是两个不同的概念 
但是要注意:通常我们叙述时会把指针变量简称为指针,实际它们含义并不一样

为什么使用指针

直接访问硬件 (opengl 显卡绘图

快速传递数据(指针表示地址
返回一个以上的值(返回一个数组或者结构体的指针
表示复杂的数据结构(结构体
方便处理字符串

*号的三种含义

*号的含义 

数学运算符: 3 * 5 
定义指针变量: int * p 
指针运算符(取值): *p (p的内容(地址)在内存中的值)

指针练习互换两个数字

swap(int* i, int* j) { // 引用传递

     int temp = *i;

       *i = *j;

       *j = temp; 

}

 

main() {

       int i = 89;

       int j = 10;

      swap(&i, &j);

      printf("i=%d\n", i);

       printf("j=%d\n", j);

      system("pause");

}

指针练习函数返回一个以上的值

change(int* a, int* b) {

    *a = 1;

    *b = 2;

}

 

main() {

    int a = 3, b = 5;

    change(&a, &b);

    printf(“a=%d, b=%d\n”, a, b);

    system(“pause”);

}

指针和数组的关系

数组名 

int a[5]; // a是数组名,5是数组的大小,元素个数 
数组名称是个指针常量,它存放的是数组中第一个元素的地址 
int a[5]; 
&a[0]
等价于 &a 
下标和指针的关系 
int a[5]; 
a[i]
等价于 *(a + i) // 这里i的范围是0~4(数组长度 -1)

指针的长度

不管什么类型的指针都是4个字节.(64位系统8字节

C语言为了方便指针运算, 定义各种基本类型的指针, 每种类型的指针运算时所偏移量的值是根据类型的长度决定的.

多级指针

int i = 10; 

int* p1 = &i; // 一级指针 
int** p2 = &p1; //
二级指针 
int*** p3 = &p2; //
三级指针 
int**** p4 = &p3; //
四级指针 
****p4 = 99; //
修改变量i的值为99;

主函数获取子函数变量地址

void function(int** p){

     int i = 4;

     *p = &i;

     printf("子函数打印i的地址为%#x\n", &i);    

}

main(){

       int* mainp;

       function(&mainp);      

       printf("主函数打印i的地址为%#x\n", mainp);    

       printf("i的值为%d\n", *mainp);

       system("pause");

 

}

静态内存和动态内存

静态内存是系统是程序编译执行后系统自动分配,由系统自动释放, 静态内存是栈分配的

动态内存是开发者手动分配的, 是堆分配的
栈内存 
*
系统自动分配 
*
系统自动销毁 
*
连续的内存区域 
*
向低地址扩展 
*
大小固定 
*
栈上分配的内存称为静态内存 
堆内存 
*
程序员手动分配 
* java
new * cmalloc 
*
空间不连续 
*
大小取决于系统的虚拟内存 
* C
:程序员手动回收free 
* java
:自动回收 
*
堆上分配的内存称为动态内存

申请堆内存

malloc(memory allocate) 函数 

malloc 申请一块堆内存

free(地址); 回收内存 

回收malloc 申请的堆内存

realloc re- allocate 

重新申请一块堆内存

结构体

struct Student {

    int age;

    float score;

    char sex;

};

 

main() {

    struct Student stu = {18, 88.5, 'M'};

}

使用结构体变量

struct Student stu = {80,55.5,'F'};

struct Student stu2;

stu2.age = 10;

stu2.score = 88.8f;

stu2.sex= ‘M';

 

printf("%d %f %c\n", st.age, st.score, st.sex);

 

// 结构体指针

struct Student * pStu;

pStu = &stu;

pStu->age 在计算机内部会被转换为 (* pStu).age

 

pStu ->age的含义: pStu所指向的结构体变量中的age这个成员

函数的指针

1.定义int (*pf)(int x, int y); 

2.赋值 pf = add; 
3.
引用 pf(3,5); 
4.
结构体中不能定义函数,只能声明函数指针

Union 联合体

struct Date {

      int year;

      int month;

      int day;

};

union Mix {

     long i;

     int k;

     char ii;

};

main() {

       printf("date:%d\n",sizeof(struct Date));

       printf("mix:%d\n",sizeof(union Mix));

       system("pause");

}

枚举

enum WeekDay {

     Monday=0,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday

};

 

main() {

       enum WeekDay day = Sunday;

       printf("%d\n",day);

       system("pause");

}

typedef

声明自定义数据类型,配合各种原有数据类型来达到简化编程的目的的类型定义关键字。

#include <stdio.h>

#include <stdlib.h>

typedef int i;

typedef long l;

main() {

       i m = 10;

       l n = 123123123;

       printf("%d\n", m);

       printf("%ld\n", n);

       system("pause");      

}

JNI 协议

NDK HelloWorld

1.创建一个android工程 

2.java代码中写声明native方法 
3.
创建jni目录,编写c代码,方法名字要对应 
4.
编写Android.mk文件 
5.NDK
编译生成动态链接库 
6.java
代码load动态库.调用native代码

javah 生成头文件

注意: 不同版本的JDK操作方式不同.

命令: javah <包名+类名>

JDK1.6使用方式 

在工程的bin/classes目录下, 执行javah命令
JDK1.7
使用方式 
在工程的src目录下, 执行javah命令.

NDK 简便开发流程

1.     关联NDK: Window -> Preferences -> Android -> NDK

2.     创建Android工程, 声明native方法.

3.     设置函数库名字: 右键工程 -> Android Tools -> App Native support

4.     使用javah生成.h的头文件, 并把.h文件拷贝到工程下jni文件夹中.

5.     c代码提示: 右键工程 -> Properties -> C/C++ General -> Path and Symbols // Includes -> Add -> File system 选中以下路径.latforms\android-18\arch-arm\usr\include

6.     把后缀名.cpp改成.c, 实现native方法.

7.     java代码中加载动态库, 调用native方法.

java c之间的数据传递

public native int add(int x, int y); 

public native String sayHelloInC(String s); 
public native int[] arrElementsIncrease(int[] intArray);

c代码中使用logcat

Android.mk文件增加以下内容

LOCAL_LDLIBS += -llog

C代码中增加以下内容

#include <android/log.h>

#define LOG_TAG "System.out"

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

C代码中使用logcat, :

LOGI("info\n");

LOGD("debug\n");

C语言调用java方法

C调用java空方法 

public void helloFromJava(){ 
C调用java中的带两个int参数的方法 
public int add(int x,int y) { 
C
调用java中参数为string的方法 
public void printString(String s){ 
}

JNI 方法签名

签名类型 Java类型 

Z boolean 
B byte 
C char 
S short 
I int 
J long 
F float 
D double 
L全类名; 引用类型 
[
类型数组

C语言回调java静态方法

C语言调用下面静态方法.

    public static void sayHello(String text) {

        System.out.println("MainActivity:showText: " + text);

    }

 

C语言回调java刷新界面

C语言调用下面Activity中方法, 弹出吐司.

    public void showToast(String text) {

        Toast.makeText(this, text, 0).show();

    }

 

eclipse找不到ndk选项解决办法

NDK插件 com.android.ide.eclipse.ndk_23.0.2.1259578.jar 如果在eclipse里配置ndk却发现没有配置的选项,则需要此插件,放置在eclipse/plugins下,重启即可。

AM命令

am命令 :adb shell里可以通过am命令进行一些操作如启动activity Service 启动浏览器等等 

am命令的源码在Am.java, adb shell里执行am命令实际上就是启动一个线程执Am.javamain方法,am命令后面带的参数都会当作运行时的参数传递到main函数中 
am
命令可以用start子命令,并且带指定的参数 
常见参数: -a: action -d data -t 表示传入的类型 -n 指定的组件名字 
举例: adb shell中通过am命令打开网页 
am start –user 0 -a android.intent.action.VIEW -d 
 
通过am命令打开activity 
am start –user 0 -n com.ngyb.cpphello/com.ngyb.cpphello.MainActivity

execlp

execlp c语言中执行系统命令的函数 

execlp() 会从PATH环境变量所指的目录中查找符合参数file的文件找到后就执行该文件, 第二个参数开始就是执行这个文件的 args[0],args[1] 最后一个参数用(char*)NULL结束 
android
开发中 execlp函数对应androidpath路径为 
system/bin/
目录 
调用格式 
execlp(“am”, “am”, “start”, “–user”,”0”,”-a”, “android.intent.action.VIEW”, “-d”, “
“, (char *) NULL);

execlp(“am”, “am”, “start”, “–user”,”0”, “-n” , “com.ngyb.cforktest/com.ngyb.cforktest.MainActivity”,(char *) NULL);

 

 

转载于:https://www.cnblogs.com/nangongyibin/p/10465078.html

你可能感兴趣的文章
Windbg内核调试之二: 常用命令
查看>>
【项目管理】工作第一步:需求分析
查看>>
「Android设计模式之旅」——设计模式的6大原则
查看>>
二、存储架构演变
查看>>
LVM报错:New size given (4096 extents) not larger
查看>>
ASA842双链路SLA配置测试
查看>>
再谈值类型和引用类型
查看>>
在Silverlight中使用Socket进行通信(3)简单的文本聊天工具
查看>>
浅谈LINQ to SQL集成数据库语言优劣
查看>>
RHCE系列之文件管理----硬链接和软链接
查看>>
三、ORM(Object/Relational Mapper)---Hibernate对象映射
查看>>
Spring3 整合 Hibernate4实现数据库操作(1)
查看>>
你所不知的IP地址管理
查看>>
iis权限导致worldclient邮件显示问题
查看>>
介绍几个c++的IDE
查看>>
0utLook 2010打开后无法连接到CAS 阵列名
查看>>
Zabbix优化: 数据库表分区
查看>>
UTC时间同步故障
查看>>
浅谈Oracle分区表之范围分区
查看>>
IBM Tivoli NetView网管软件实战
查看>>