首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > 移动开发 >

本土方法调用1

2012-07-15 
本地方法调用1啊,好久没写blog了,更新还真是不适应。这个。。。话说,婚假回来,就一直没有感觉,虽然现在感觉也

本地方法调用1
啊,好久没写blog了,更新还真是不适应。这个。。。话说,婚假回来,就一直没有感觉,虽然现在感觉也不是很好,但还是要hold住~
今天开始要搞一搞jni了,不然一年也屡不清原计划啊。
java的书从来都说的很好,100%纯java的解决方案是非常好的,但是,java性能真的还是不如c和c++。一般的辩解会是:网络io才是真正的瓶颈等等云云。ok,没错,但是(当然要有但是啦。一?这句话怎么这么熟?),java的速度确实不如c和c++,导致在很多时候,如用户响应上,确实有时会有不顺畅的感觉。当然,瑕不掩瑜,在很多时候,java还是非常强的,并且很难替代。
今天,先来一节入门篇,讲讲如何从java调到c函数的。
首先是native申明。
native声明一个方法后,就不用再写方法体了,因为实现是在下面进行。
来看看code:

class HelloNative{    public static native void greeting();}

注意,static不是必须的。
你实际可以使用这个类,但是在程序中使用它时,虚拟机就会告诉你它不知道如何找到greeting,它会报告一个UnsatisfiedLinkError异常。为了实现本地代码,需要编写一个响应的c函数,你必须要完全按照java规则来命名这个函数:
1)使用完整的java方法名,比如:HelloNativ.greeting。如果类输入某个包,那么前面添加报名,比如:com.horstmann.HelloNative.greeting。
2)用下划线替换掉所有的句号,并加上Java_前缀,例如,Java_HelloNative_greeting或者Java_com_horstmann_HelloNative_greeting。
3)如果类名含有非ASCII字母或数字,如:‘_’,‘$’或是大于‘\u007f’的Unicode字符,用_0xxxx来替代它们,xxxx是该字符的值的4个十六进制数。
(注意,如果有两个方法 greeting()和greeting(int i),那么必须在后缀附加两个下划线,后面加上已编码的参数类型:Java_HelloNative_greeting__和Java_HelloNative_greeting__I)
很麻烦吧?别紧张,这些东西,是能够自动生成的,先使用javac对java文件编译,然后使用javah,生成如下:
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class HelloNative */#ifndef _Included_HelloNative#define _Included_HelloNative#ifdef __cplusplusextern "C" {#endif/* * Class:     HelloNative * Method:    greeting * Signature: ()V */JNIEXPORT void JNICALL Java_HelloNative_greeting  (JNIEnv *, jclass);#ifdef __cplusplus}#endif#endif

接下来我们只用在HelloNative.c的文件中实现这个声明了的方法就好了:
#include "HelloNative.h"#include <stdio.h>JNIEXPORT void JNICALL Java_HelloNative_greeting  (JNIEnv* env, jclass cl){    printf("hello native world!\n");}

C++也是可以的:
extern "C"JNIEXPORT void JNICALL Java_HelloNative_greeting  (JNIEnv* env, jclass cl){    cout<<"hello native world!"<<endl;}

ok,我们可以把这个.c文件在linux下编译了,命令:
gcc -fPIC -I jdk/include -I jdk/include/linux -shared -o libHelloNative.so HelloNative.c

好了,生成的so就可以使用了,当然,为了确保虚拟机第一时间把库load进去,我们要使用静态初始化代码块:
class HelloNativeTest{    static{        System.loadLibrary("HelloNative");    }    public static void main(String[] args){        HelloNative.greeting();    }}

在linux在,必须把当前目录添加到库路径中。实现方式可以通过设置LD_LIBRARY_PATH环境变量:
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
或者是设置java.library.path系统属性
java -Djava.library.path=. HelloNaticeTest
好了,java可以找到我们了。

一些本地代码的共享库必须先运行初始化代码。你可以把初始化代码放到JNI_OnLoad方法中。类似的,如果你提供该方法,当虚拟机关闭时,将会调用JNI_OnUnload方法。
它们的原型是:
jint JNI_OnLoad(JavaVM* vm, void* reserved);
void JNI_OnUnLoad(JavaVM* vm, void* reserved);
OnLoad返回所需的虚拟机的最新版本,如:
JNI_VERSION_1_2.

现在,从上到下的调用都讲明白了,下次,我们再继续深入吧。 我在编译so库的时候报以下错误:指点指点

error: expected constructor, destructor, or type conversion before ‘void’ 我在编译so库的时候报以下错误:指点指点

error: expected constructor, destructor, or type conversion before ‘void’


我知道原因了:jni.h的位置没有给正确。现在已经可以了! 我在编译so库的时候报以下错误:指点指点

error: expected constructor, destructor, or type conversion before ‘void’


我知道原因了:jni.h的位置没有给正确。现在已经可以了!
好吧,刚看到你的留言。。。

热点排行