jni helloworld 验证成功

第一步,定义一个 Java 类 -- Hello. 它提供SayHello方法:

此时应注意两点:

1.为要使用的每个本地方法编写本地方法声明,其声明方式与普通 Java 方法接口没什么不同,只是必须指定 native 关键字,如下所示:

public native void SayHello(String strName);

在这个函数中,我们将根据传进的人名,向某人问好。

2.必须显式地加载本地代码库。当然要调用System.loadLibrary("hello");注 意此时不要lib,也不要.so!; 我们需在类的一个静态块中加载这个库:

static

    {

    System.loadLibrary("hello");

    }

       

 

再加上必要的异常处理就生成如下源文件Hello.java:

public class Hello

{

        static

        {

              

            System.loadLibrary("hello");

         }

//声明的本地方法

       public  staitc native void sayHello(String strName);

}

运行命令 javac Hello.java 生成Hello.class文件。

第二步,生成本地链接库。具体过程如下:

1. 要为以上定义的类生成 Java 本地接口头文件,需使用javah,Java 编译器的 javah 功能将根据 Hello类生成必要的声明,此命令将生成Hello.h 文件,我们在共享库的代码中要包含它,javah不使默认内部命令,需要指明路径,它在JDK的bin目录下,在我的Linux环境下命令如下:

javah Hello

但是出现如下错误:

error: cannot access Hello

class file for Hello not found

javadoc: error - Class Hello not found.

Error: No classes were specified on the command line.  Try -help.

原因是CLASS_PATH没有把当前目录加入其中。所以必须指定classpath 为当前目录。或者在系统CLASS_PATH加入当前路径。执行如下命令:

javah -classpath . Hello

生成的Hello.h 文件内容的第一句子为 #include <jni.h> 
但是gcc里面默认环境可不知道jni.h是什么东西,jni.h在jdk 的$JAVA_HOME/include下面,可进去查看一下~

2.在与Hello.h相同的路径下创建一个CPP文件Hello.cpp。注意,自动生成的那个函数名字很长,并且 开头的  Java是大写的,大小写很致命一定要注意。内容如下:

#include "Hello.h"

#include <stdio.h>

//与Hello.h中函数声明相同

JNIEXPORT void JNICALL Java_Hello_sayHello  (JNIEnv * env, jclass arg, jstring instring)

{

   //从instring字符串取得指向字符串UTF编码的指针

const jbyte *str =

        (const jbyte *)env->GetStringUTFChars( instring, JNI_FALSE );

    printf("Hello,%s/n",str);

        //通知虚拟机本地代码不再需要通过str访问Java字符串。

    env->ReleaseStringUTFChars( instring, (const char *)str );

    return;

}

 

所有的JNI调用都使用了JNIEnv *类型的指针,习惯上在CPP文件中将这个变量定义为env,它是任意一个本地方法的第一个参数。env指针指向一个函数指针表,在VC中可以直接 用"->"操作符访问其中的函数。

jobject 指向在此 Java 代码中实例化的 Java 对象 LocalFunction的一个句柄,相当于this指针。

后续的参数就是本地调用中有Java程序传进的参数,本例中只有一个String型参数。 对于字符串型参数,因为在本地代码中不能直接读取 Java 字符串,而必须将其转换为 C /C++字符串或 Unicode。以下是三个我们经常会用到的字符串类型处理的函数:

const char* GetStringUTFChars(jstring string,jboolean* isCopy)

3.编译生成共享库。

使用GCC时,必须通知编译器在何处查找此 Java 本地方法的支持文件,并且显式通知编译器生成位置无关的代码,在我的环境中按如下过程编译:

g++ -I /usr/lib/jvm/java-6-sun/include/linux/ -I /usr/lib/jvm/java-6-sun/include/ -fPIC -c Hello.cpp

生成Hello.o

g++ -shared -Wl,-soname,libhello.so.1 -o libhello.so.1.0 Hello.o

生成libhello.so.1.0

接下来将生成的共享库拷贝为标准文件名

cp libhello.so.1.0 libhello.so

或者使用:

g++ -I /usr/lib/jvm/java-6-sun/include/linux/ -I /usr/lib/jvm/java-6-sun/include/ -fPIC -shared -o libLexical.so Lexical.cpp 

 注意在linux下,动态链接库的名字 必须是 lib****.so,必须以lib开头! 
4.编写一个简单的Java程序来测试我们的本地方法。

将如下源码存为ToSay.java:

public class ToSay

{

        public static void main(String argv[])

        {

              Hello.sayHello("John");    

        }

}

 

用javac编译ToSay.java命令javac -cp . ToSay.java,生成ToSay.class。 
向执行普通Java程序一样使用java ToSay,

java ToSay

Exception in thread "main" java.lang.NoClassDefFoundError: ToSay

Caused by: java.lang.ClassNotFoundException: ToSay

       at java.net.URLClassLoader$1.run(URLClassLoader.java:202)

       at java.security.AccessController.doPrivileged(Native Method)

       at java.net.URLClassLoader.findClass(URLClassLoader.java:190)

       at java.lang.ClassLoader.loadClass(ClassLoader.java:307)

       at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)

       at java.lang.ClassLoader.loadClass(ClassLoader.java:248)

Could not find the main class: ToSay.  Program will exit.

原因是classpath没有当前路径。改正后执行如下命令:

 java -cp . ToSay

Exception in thread "main" java.lang.UnsatisfiedLinkError: no hello in java.library.path

       at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1734)

       at java.lang.Runtime.loadLibrary0(Runtime.java:823)

       at java.lang.System.loadLibrary(System.java:1028)

       at Hello.<clinit>(Hello.java:6)

       at ToSay.main(ToSay.java:5)

依然报错。java.lang.UnsatisfiedLinkError: no HelloNative in java.library.path。这个错误很经典,原因:是java找不到库路径~: 显然: libhello.so放在当前路径 ".",只linux执行的时候却不知道在当前路径找。 
a. linux下面java.library.path 和环境变脸 jdk/bin的那个个PATH不是一回事情,有另外一个默认变量 LD_LIBRARY_PATH来保存他的信息。而windows下,首先java会找当前目录,其次,它会去环境变量的地址找! 
b。 由于linux的路径特殊,所以,解决方法 1-可以调用sysout(System.getProperty("java.library.path")); 来查看! 然后把libXXXX.so拷贝到那里面的目录下去 
2 设置环境变量 export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH 
3 可以单次执行时候指定library位置: 
  java -Djava.library.path=.  -cp . ToSay

我们会看到在屏幕上出现Hello,John。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值