JNI:Java Native Interface 缩写(Java本地接口)
JNI是一种本地编程的接口。它允许运行在JAVA虚拟机中的Java代码和其他编程语言相互调用,
比如,c/c++ 写的应用和库之间的相互操作。
作用:
JNI允许我们用其他编程语言来解决用纯粹的java代码不好处理的情况,比如调用一些基于JNI的其他语言的I/O,音视频
相关功能的库,当然也有各种高性能的程序,也用于改造已存在的用其他语言写的程序,供java程序调用。
JNI框架允许Native方法调用Java对象,就像Java程序访问Native对象一样方便。Native方法可以创建Java对象,读取这些
对象,并调用Java对象执行某些方法。当然Native方法也可以读取由Java程序自身创建的对象,并调用这些对象的方法。
缺点:
JNI没有 JVM内存垃圾回收机制,需要使用代码进行显示的释放。
JNI在有些情况下可能带来很呆的开销和性能的损失:
1.调用 JNI 方法是很笨重的操作,特别是在多次重复调用的情况下。
2.Java 数组传递给 native 方法时,可能需要拷贝过去,执行完再拷贝回来,开销较大,需要使用多块内存。
3.Native方法需要使用Java的相关方法属性是,需要类似反射的东西,访问Java对象的属性、方法,非常缓慢容易出错。
4.使用字符串、对象时非常不灵活,需要单独获取。
一个JNI函数看起来时这样的:
extern "C" //是为了 C与C++ 混编,按照C语言的方式编译 如果这里是.cpp文件的话,就需要加,如果是.c 文件则不需要
JNIEXPORT void JNICALL Java_ClassName_MethodName
( JNIEnv *env, jobject obj)
{
}
大家可以看到这个JNI方法。
这里 JNIEXPORT 和 JNICALL ,定义在jni_md.h头文件中
JNIEXPORT:
在Windows中,定义为__declspec(dllexport)。因为Windows编译dll动态库规定,如果动态库中的函数要被外部调用,
需要在函数声明中添加此标识,表示将该函数导出在外部可以调用。
在 Linux/Unix/Mac os/Android 这种 Like Unix系统中,定义为`__attribute__((visibility ("default")))
JNICALL:
在类Unix中无定义,在windows中定义为: _stdcall,一种函数调用约定
类Unix系统中这两个宏可以省略不加。
然后JNI函数默认被传递一个JNIEnv指针,一个jobject的指针。
JNIEnv: 由Jvm传入与线程相关的变量。定义了JNI系统方法,java交互等方法。
jobject:表示当前调用对象,即 java 中 this ,如果是静态的Native方法,则获得jclass。
自己编写应该是这样的:
这是对应的java代码
native String test(int i,String j,float k);
extern "C" //因为我这里是 .cpp 文件
JNIEXPORT jstring JNICALL Java_com_example_costomviewtext_ExampleUnitTest_test
(JNIEnv *env, jobject, jint i,jstring j, jfloat k)
{
//获得c字符串
//参数1 这个字符串
//参数2 是否复制
const char* str = env->GetStringUTFChars(j,JNI_FALSE);
//释放掉内存x
env->ReleaseStringUTFChars(j, str);
//返回字符串
return env->NewStringUTF(returnStr);
}
jstring 在这里对应的是 Java中的 string 类型,这里代表返回值,可以对应上面Java代码其实也可以看出来。
Java_com_example_costomviewtext_ExampleUnitTest_test
这个就是JNI的函数命名规范了, Java没什么好说的,咱们看后面的,
com.example.costomviewtext 这个就是我Android项目对应的包名了,然后ExampleUnitTest 是类名 ,
最后test是方法名, 然后这些中间用 _ 连接,这边就有个坑了,就说咱们Android中包名命名中可以使用 _ 这个,在这里
如果直接使用,不做处理会有问题,系统会默认处理成连接包名的, 这种情况我们要写成 _1 , 就是在后面加个1,这样系统
就按包名处理了。
比如 : com.example.costomview_text 如果我的包名是这个的话,
这里我的JNI就得写成 com_example_costomview_1text 这样。
说完这个我们看看 JNI的 数据类型 与Java中的对应关系:
还有基本数据类型对应的签名,这个在后面Native 反射 Java时会有使用,这里不懂也没关系。
好了,本篇先写这么多,内容不是很多,主要是先简单了解一下JNI相关的一些简单的东西,这样在后面几篇中就
容易理解了。