一、环境准备
Windows7 + WMwareWorkstation9 + RedHatEnterprise5 + jdk1.7.0_51
我的jdk安装路径为 /usr/java/jdk1.7.0_51
二、步骤
1.编写Java代码 Hello.java
package org.bt.hello;
public class Hello{
private String name = "bigtree";
/* 无参构造函数 */
public Hello(){
}
/* 带参数的构造函数 */
public Hello(String name){
this.name = name;
}
/* 声明本地函数,返回一个类对象(使用无参构造函数) */
private static native Hello getObjNoParm();
/* 声明本地函数,返回一个类对象(使用带参数的构造函数) */
private static native Hello getObjWithParm();
private void print(){
System.out.println(name + "Hello world!");
}
/* 加载共享库 */
static {
System.loadLibrary("bigtree");
}
public static void main(String []args){
Hello obj = getObjNoParm();/* 调用本地函数,得到一个Hello对象 */
obj.print();/* 使用对象调用函数 */
Hello obj1 = getObjWithParm();
obj1.print();
}
}
2.编译Java代码,生成Java字节码文件.class
$ javac -d . Hello.java
3.使用javah生成头文件
$ javah org.bt.hello.Hello
4.编写C函数,包含头文件,实现本地函数 hello.c
#include "org_bt_hello_Hello.h"
JNIEXPORT jobject JNICALL Java_org_bt_hello_Hello_getObjNoParm(JNIEnv *env, jclass jcls){
/* 得到类的字节码信息,其中第二个参数为包名+类名 */
jclass helloClass = (*env)->FindClass(env, "org/bt/hello/Hello");
/* 得到构造函数的方法id,第二个参数为类的信息,因为是构造函数,因此第三个参数为<init>,第四个参数为函数签名 */
jmethodID conId = (*env)->GetMethodID(env, helloClass, "<init>", "()V");
/* 调用构造函数,创建对象 */
jobject helloObj = (*env)->NewObject(env, helloClass, conId);
return helloObj;
}
JNIEXPORT jobject JNICALL Java_org_bt_hello_Hello_getObjWithParm(JNIEnv *env, jclass jcls){
/* 得到类的字节码信息 */
jclass helloClass = (*env)->FindClass(env, "org/bt/hello/Hello");
/* 得到构造函数的方法id */
jmethodID conId = (*env)->GetMethodID(env, helloClass, "<init>", "(Ljava/lang/String;)V");
/* 构造参数 */
jstring jname = (*env)->NewStringUTF(env, "zhangsan");
/* 调用构造函数,创建对象 */
jobject helloObj = (*env)->NewObject(env, helloClass, conId, jname);
return helloObj;
}
5.制作共享库libbigtree.so
$ gcc -fPIC -I /usr/java/jdk1.7.0_51/include -I /usr/java/jdk1.7.0_51/include/linux/ -shared -o libbigtree.so hello.c
6.运行Java程序,测试结果
$ java org/bt/hello/Hello
打印结果为:bigtreeHello world!
zhangsanHello world!
表示jni创建Java类对象成功,并且返回成功。
三、函数签名、类型签名
类型签名
类型 签名 类型 签名
byte | B | byte [] | [B |
short | S | short [] | [S |
int | I | int [] | [I |
long | J | long [] | [J |
float | F | float [] | [F |
double | D | double [] | [D |
char | C | char [] | [C |
boolean | Z | boolean [] | [Z |
java.lang.String | Ljava/lang/String; | String [] | [Ljava/lang/String; |
java.lang.Object | Ljava/lang/Object | object [] | [Ljava/lang/Object; |
org.bt.hello.Hello Lorg/bt/hello/Hello; int [][] [[I
Hello [](对象数组) [Lorg/bt/hello/Hello;
注意:签名是Java层和jni层的对应关系,Java层类型可以自动转换到jni层类型,jni层类型不能自动转换,部分可以自动转换,基本上要手动转换,一般调用函数。
当Java层的类型是引用类型时,对应的jni层的类型为L+包名+类名+分号,切记分号在这里不是分隔符,是类型的一部分。
函数签名
类型 签名
String f() | ()Ljava/lang/String; |
long f(int i, Stu stu) | (ILorg/bt/Stu;)J |
void s(byte [] byte) | ([B)V |
Stu f(Object o, String s, int i) | (Ljava/lang/Object;Ljava/lang/String;I)Lorg/bt/Stu; |
其他类型的函数签名依此类推。。。。
转载于:https://blog.51cto.com/happytree007/1553519