JNI的初步了解与简单示例
2015-04-16 20:55
351 查看
说实在的,我只是知道jni的意思,但是真正运用到jni的事例却是没有过,所以对jni真的是没怎么去了解过,但是现在看来,学习jni真的是很有必要,在很多方面可能对你会很有帮助,或者对你技术的提升会有很大的帮助。
首先我们来先了解jni到底是什么?它有什么作用?我们为什么要学习它,什么情况需要用到jni?然后我们在通过几个demo来学习一下。
Jni的全称是java native interface(java的本地接口),说白了就是java调用的本地的c、c++的接口,所以我们可以猜到jni就是java调用本地的c/c++方法来完成自身程序功能的一个工具。我们设想一下啊,如果你的Java代码,需要得到一个文件的属性,但是你找遍了JDK帮助文档也找不到相关的API;如果本地有一个其他的项目,不过不是Java语言实现的,而是其他语言实现的,这个时候你的老板要求你把两套系统整合到一起,你会怎么整合呢?
如果你的Java代码中需要用到某种算法,不过算法是用C实现并封装在动态链接库文件(DLL)当中的,你要怎么去调用呢?还有就是我之前说多的物联,底层的硬件是有c语言控制的,你的app要实现硬件的一些操作,你会怎么去调用呢?而且,用jni也大大增加了程序的安全性,反编译的出来的概率大大减小。
当然,jni也是有一些缺点的,就是不是很智能,写类,方法,都要自己去jni文件中找,也没有提示,大大降低了编码的效率。
Jni很好的帮我们解决了这一些问题。
下面我们通过几个demo来学习一下如何使用jni:
1.简单的helloworld
似乎所有的程序员都是从helloworld开始的,ok,这些demo我都是在虚拟机完成的,不过不用虚拟机也可以,先不用ide来写我们的demo,直接用记事本写就可以了,这主要是为了方便直观,先写一个java类:
public class Jason
{
//native修饰符:此方法不是抽象方法,它的实现体在本地语言中
public native void printHelloworld(String str);
/*
public void printHelloworld()
{
System.out.println(“hello world”);
}
*/
}
接着编译一下java类,在用javah编译一下java类生成头文件(c类的),就是Jason.h文件,在根据.h文件编写c类:
/* DO NOT EDIT THIS FILE - it is machine generated */
(JNIEnv *env, jobject obj, jstring str)
{
}
其中那些如GetStringUTFChars方法可以在jdk中jni文件中查询,这个方法是将string类转换成char类,之所以转换是因为c语言输出的都是char类,没有string,写完之后要生成.so文件,就是动态库了,我都是放在同一个文件夹的,用的是cmd编译,所以要输入一下命令行
其中的gccxxxx xxx.so xxx.c 就是根据c文件来生成动态库,还要把动态库考在java.library.path这个路径,不然要报错,至于这个路径怎么找,可以写一下代码:
public class GetJavaLibraryPath
{
public static void main(String[]args)
{
String path=System.getProperty(“java.library.path”);
}
返回的就是java.library.path路径,考到其中的一条路径就好了,cp -a xxx.so usr/lib 就是将动态库考到usr中lib文件里面,接着直接运行java就可以了。
2 从c库中获取参数的demo
先编写java类:
public class PrintHelloWorld
{
//native修饰符:此方法不是抽象方法,它的实现体在本地语言中
public native void printHelloworld(String str);
public native String gecCStr();
public static void main(String[]args)
{
PrintHelloWorld t=new PrintHelloWorld();
String str=t.gecCStr();
System.out.println(str);
}
}
接着编译生产class和.h,在根据.h来编写c文件,步骤跟1差不多,
(JNIEnv *env, jobject obj, jstring str)
{
}
JNIEXPORT jstring JNICALL Java_PrintHelloWorld_gecCStr
(JNIEnv *env, jobject obj)
{
}
这些方法就是在jni文件中找的,//jstring (JNICALL *NewStringUTF)(JNIEnv *env, const char *utf);,这个const char *utf就是我们要返回的java的参数值,这个方法是将他转成字符串。接下来步骤跟1一样,生产.so跟拷贝,这里就不累赘了。
3在c库中调用java类中的方法demo
public class PrintHelloWorld
{
}
Java代码中我们可以看到main函数中是没有调用callBackListener方法,就是没有任何输出方法,接下来一样生成编写c文件:
(JNIEnv *env, jobject obj, jstring str)
{
}
JNIEXPORT jstring JNICALL Java_PrintHelloWorld_gecCStr
(JNIEnv *env, jobject obj)
{
return (void*)0;
}
JNIEXPORT void JNICALL Java_PrintHelloWorld_accessField
(JNIEnv *env, jobject obj)
{
}
JNIEXPORT void JNICALL Java_PrintHelloWorld_setFieldValue
(JNIEnv *env, jobject obj)
{
}
这个前两个demo一样,都是要从jni中找对应的方法,其中const char *sig这个指的是变量或者方法在java中的签名,可以用javap -s -p xxx(java类)来查看签名。
至于,jni在eclipse中如何使用,这个我会在后面见到,这里还涉及到一个叫NDK的东西,是帮助我们在eclipse中编写jni的。
首先我们来先了解jni到底是什么?它有什么作用?我们为什么要学习它,什么情况需要用到jni?然后我们在通过几个demo来学习一下。
Jni的全称是java native interface(java的本地接口),说白了就是java调用的本地的c、c++的接口,所以我们可以猜到jni就是java调用本地的c/c++方法来完成自身程序功能的一个工具。我们设想一下啊,如果你的Java代码,需要得到一个文件的属性,但是你找遍了JDK帮助文档也找不到相关的API;如果本地有一个其他的项目,不过不是Java语言实现的,而是其他语言实现的,这个时候你的老板要求你把两套系统整合到一起,你会怎么整合呢?
如果你的Java代码中需要用到某种算法,不过算法是用C实现并封装在动态链接库文件(DLL)当中的,你要怎么去调用呢?还有就是我之前说多的物联,底层的硬件是有c语言控制的,你的app要实现硬件的一些操作,你会怎么去调用呢?而且,用jni也大大增加了程序的安全性,反编译的出来的概率大大减小。
当然,jni也是有一些缺点的,就是不是很智能,写类,方法,都要自己去jni文件中找,也没有提示,大大降低了编码的效率。
Jni很好的帮我们解决了这一些问题。
下面我们通过几个demo来学习一下如何使用jni:
1.简单的helloworld
似乎所有的程序员都是从helloworld开始的,ok,这些demo我都是在虚拟机完成的,不过不用虚拟机也可以,先不用ide来写我们的demo,直接用记事本写就可以了,这主要是为了方便直观,先写一个java类:
public class Jason
{
//native修饰符:此方法不是抽象方法,它的实现体在本地语言中
public native void printHelloworld(String str);
/*
public void printHelloworld()
{
System.out.println(“hello world”);
}
*/
public static void main(String[]args) { PrintHelloWorld t=new PrintHelloWorld(); t.printHelloworld("weclome to gz"); } //静态加载动态库libjasonhello.so static{ System.loadLibrary("jasonhello"); }
}
接着编译一下java类,在用javah编译一下java类生成头文件(c类的),就是Jason.h文件,在根据.h文件编写c类:
/* DO NOT EDIT THIS FILE - it is machine generated */
include “PrintHelloWorld.h”
include “stdio.h”
JNIEXPORT void JNICALL Java_Jason_printHelloworld(JNIEnv *env, jobject obj, jstring str)
{
const char* cstr=(*env)->GetStringUTFChars(env,str,0); //const char* (JNICALL *GetStringUTFChars) //(JNIEnv *env, jstring str, jboolean *isCopy); printf("%s \n",cstr);
}
其中那些如GetStringUTFChars方法可以在jdk中jni文件中查询,这个方法是将string类转换成char类,之所以转换是因为c语言输出的都是char类,没有string,写完之后要生成.so文件,就是动态库了,我都是放在同一个文件夹的,用的是cmd编译,所以要输入一下命令行
其中的gccxxxx xxx.so xxx.c 就是根据c文件来生成动态库,还要把动态库考在java.library.path这个路径,不然要报错,至于这个路径怎么找,可以写一下代码:
public class GetJavaLibraryPath
{
public static void main(String[]args)
{
String path=System.getProperty(“java.library.path”);
System.out.println(path); }
}
返回的就是java.library.path路径,考到其中的一条路径就好了,cp -a xxx.so usr/lib 就是将动态库考到usr中lib文件里面,接着直接运行java就可以了。
2 从c库中获取参数的demo
先编写java类:
public class PrintHelloWorld
{
//native修饰符:此方法不是抽象方法,它的实现体在本地语言中
public native void printHelloworld(String str);
public native String gecCStr();
public static void main(String[]args)
{
PrintHelloWorld t=new PrintHelloWorld();
String str=t.gecCStr();
System.out.println(str);
}
//静态加载动态库libgechelloworld78_03.so static{ System.loadLibrary("gechelloworld78_03"); }
}
接着编译生产class和.h,在根据.h来编写c文件,步骤跟1差不多,
include “PrintHelloWorld.h”
JNIEXPORT void JNICALL Java_PrintHelloWorld_printHelloworld(JNIEnv *env, jobject obj, jstring str)
{
}
JNIEXPORT jstring JNICALL Java_PrintHelloWorld_gecCStr
(JNIEnv *env, jobject obj)
{
const char *cstr="c hello world"; //jstring (JNICALL *NewStringUTF) //(JNIEnv *env, const char *utf); jstring returnString=(*env)->NewStringUTF(env,cstr); return returnString;
}
这些方法就是在jni文件中找的,//jstring (JNICALL *NewStringUTF)(JNIEnv *env, const char *utf);,这个const char *utf就是我们要返回的java的参数值,这个方法是将他转成字符串。接下来步骤跟1一样,生产.so跟拷贝,这里就不累赘了。
3在c库中调用java类中的方法demo
public class PrintHelloWorld
{
int a=5; //native修饰符:此方法不是抽象方法,它的实现体在本地语言中 public native void printHelloworld(String str); public native String gecCStr(); public native void accessField(); public native void setFieldValue(); public void callBackListener(int c) { System.out.println("callBackListener c="+c); } public static void main(String[]args) { PrintHelloWorld t=new PrintHelloWorld(); t.accessField(); t.setFieldValue(); System.out.println(t.a); } //静态加载动态库libgechelloworld78_04.so static{ System.loadLibrary("gechelloworld78_04"); }
}
Java代码中我们可以看到main函数中是没有调用callBackListener方法,就是没有任何输出方法,接下来一样生成编写c文件:
include “PrintHelloWorld.h”
JNIEXPORT void JNICALL Java_PrintHelloWorld_printHelloworld(JNIEnv *env, jobject obj, jstring str)
{
}
JNIEXPORT jstring JNICALL Java_PrintHelloWorld_gecCStr
(JNIEnv *env, jobject obj)
{
return (void*)0;
}
JNIEXPORT void JNICALL Java_PrintHelloWorld_accessField
(JNIEnv *env, jobject obj)
{
//jclass (JNICALL *GetObjectClass) // (JNIEnv *env, jobject obj); jclass cls=(*env)->GetObjectClass(env,obj); //jfieldID (JNICALL *GetFieldID) //(JNIEnv *env, jclass clazz, const char *name, const char *sig); jfieldID fieldId=(*env)->GetFieldID(env,cls,"a","I"); //jint (JNICALL *GetIntField) // (JNIEnv *env, jobject obj, jfieldID fieldID); jint aValue=(*env)->GetIntField(env,obj,fieldId); printf("a=%d \n",aValue);
}
JNIEXPORT void JNICALL Java_PrintHelloWorld_setFieldValue
(JNIEnv *env, jobject obj)
{
jclass cls=(*env)->GetObjectClass(env,obj); //jfieldID (JNICALL *GetFieldID) //(JNIEnv *env, jclass clazz, const char *name, const char *si 9957 g); jfieldID fieldId=(*env)->GetFieldID(env,cls,"a","I"); (*env)->SetIntField(env,obj,fieldId,10); //void (JNICALL *SetIntField) //(JNIEnv *env, jobject obj, jfieldID fieldID, jint val); // jmethodID (JNICALL *GetMethodID) //(JNIEnv *env, jclass clazz, const char *name, const char *sig); jmethodID mId=(*env)->GetMethodID(env,cls,"callBackListener","(I)V"); //void (JNICALL *CallVoidMethod) //(JNIEnv *env, jobject obj, jmethodID methodID, ...); (*env)->CallVoidMethod(env,obj,mId,4);
}
这个前两个demo一样,都是要从jni中找对应的方法,其中const char *sig这个指的是变量或者方法在java中的签名,可以用javap -s -p xxx(java类)来查看签名。
至于,jni在eclipse中如何使用,这个我会在后面见到,这里还涉及到一个叫NDK的东西,是帮助我们在eclipse中编写jni的。
相关文章推荐
- JNI简单示例
- jni程序开发简单示例和说明(eclipse + Microsoft Visual Studio 2010)
- 深入了解ibatis源码----简单ibatis示例代码
- openGL/ESv2 通过JNI的简单示例代码
- Hibernate(1)Hibernate简介和简单示例,了解Hibernate事务回滚用法
- Mybatis(三)、mybatis执行示例和mybatis事务以及缓存跟二级缓存简单了解
- android JNI 的简单示例
- 简单完整的代码,通过这个代码你将对RSA加密算法在Java中的实现方法有一个初步的了解,这个类,你可以直接使用,水平高的,就自己修改完善下代码。
- JNI简单示例
- 详解Data Binding - 通过几个简单示例深入了解WinForm数据绑定特性
- 简单初步了解KVC
- 深入了解ibatis源码----简单ibatis示例代码
- Android Binder 机制初步学习 笔记(四,完结)—— Binder 简单应用示例
- JNI和NDK编程的简单了解
- JNI简单示例
- JNI简单示例
- 快速了解Python开发中的cookie及简单代码示例
- Struts 1 学习笔记-1(简单登录模块的实现,Struts初步了解)
- Android studio 初步使用JNI(三)简单使用JNI
- AlexNet简单理解&&CNN初步了解