C++封装成Jni库的详细步骤
C++封装成Jni库的详细步骤
前段时间⽤C++实现了⼀个数据库连接的类,类中包含了⼀些连接和断开操作。我想在java中调⽤这些功能。jni⽅法提供了只是函数接⼝的调⽤⽽没有类的调⽤(有关函数接⼝调⽤的⽹上有很多资料⾮常简单,可以⾃⾏查阅),后来决定采⽤⽤c/c++函数重新封装类⾥的操作的⽅法,使得java在调⽤时直接调⽤c/c++提供⾥⾯的函数接⼝⽽不直接调⽤类。在看该⽂时建议先看⼀下jni的使⽤。
现在⼀步步往下做。为了简化操作,这⾥不使⽤数据库连接的类,⽽是编写了⼀个有关两个整数运算的类来模拟数据库类。该类实现整数的加减乘除。这个⾮常重要,但是很普遍,可以上⽹查看⼀下,都有配置环境的介绍,这⾥不在叙述。
第⼀步:配置java环境
这个⾮常重要,但是很普遍,可以上⽹查看⼀下,都有配置环境的介绍,这⾥不在叙述。
第⼆步:实现⼀个类,包含⼀些简单操作
//Twono.h
#ifndef TWONO_H
#define TWONO_H
class TwoNo{
int i,j;
public:
TwoNo();
TwoNo(int,int);
int Add();//加
int Divide();//除
int Multi();//乘
int Sub();//减
~
TwoNo();
};
#endif
Twono.cpp
#include "twono.h"
TwoNo::TwoNo()
{
i = 0;
j = 0;
}
TwoNo::TwoNo(int a,int b)
{
i = a;
j = b;
}
TwoNo::~TwoNo()
{
}
int TwoNo::Add()
{
return i+j;
}
int TwoNo::Sub()
{
return i-j;
}
int TwoNo::Multi()
{
return i*j;
}
int TwoNo::Divide()
{
return i/j;
}
做好该类之后,我打成libTwono.so包,并将它放到/usr/lib下: g++ -fPIC -shared -o Twono.cpp
接下来为了能在java中使⽤类TwoNo中的Add⽅法,我现在在Add.java⽂件中来声明native函数add(),add()函数封装了类Twono中的Add⽅法,native限定词是实现jni本地调⽤的关键字,说明了该⽅法是需要通过其他语⾔来实现的。
//Add.java
system的头文件public  class Add
{
static
{
System.load("//usr/lib/libA.so");//libA.so是⽤C封装类操作后⽣成的包,这⾥可以先随便命名
}
public native int add(int a,int b); //声明的add()函数,在后⾯他封装了类Twono中的Add()函数
public static void  main(String[] args)
{    了
Add a = new Add();
System.out.println("hello" + a.add(3,1));
}
}
该java⽂件的预期输出结果应该是hello4.
⽤命令javac Add.java ⽣成Add.class
⽤命令javah Add ⽣成Add.h ,Add.h是后⾯Add.cpp的头⽂件,该头⽂件包含了java中映射到其他语⾔转换后的函数,具体形式如下:
//Add.h
#include <jni.h>
#ifndef _Included_Add
#define _Included_Add
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jint JNICALL Java_Add_add
(JNIEnv *, jobject, jint, jint);      //该函数就是Add.java中的add()函数,具体形式如果有不明⽩的可以上⽹查看⼀下,有⾮常多的介绍,前⾯两个参数可以⼀般不理,他是jni函数都带有的。如果
//你使⽤到java中传过来的参数类型像string之类的,但int,bool,byte之类的没必要使⽤前⾯两个参数,后⾯jint,jint 就是add()函数本⾝的参数
#ifdef __cplusplus
}
#endif
#endif
第三步:编写Add.cpp 封装类Twono中的Add()
//Add.cpp
#include "Add.h"
#include <iostream>
#include "twono.h"      //包含你所使⽤类的头⽂件
using namespace std;
JNIEXPORT jint JNICALL Java_Add_add
(JNIEnv *, jobject, jint a, jint b)
{    TwoNo t(a,b);      //声明该类
return t.Add();
}
//在.cpp中使⽤了类Twono中的Add();
第四步:将该Add.cpp⽣成动态连接库
⽣成命令: g++ -I/java/jdk1.5.0_08/include -L/usr/lib -shared -o Add.cpp -lTwono
在编译⽣成动态连接库的时候需要包含你要使⽤的类的动态链接库,上⾯的-I/java/jdk1.5.0_08/include指明了java的⼀些头⽂件,-
L/usr/lib指明了要使⽤到的⼀些类库的所在地,像libTwono.so就在它下⾯,-lTwono表⽰Add.cpp⽣成的动态链接库libA.so需要使⽤到libTwono.so⾥的函数,这些库可以包含多个,只要正确指明他的路径和名称即可
并将⽣成的libA.so放到正确位置
第五步:重新编译
重新来编译Add.java
javac Add.java
java Add
如果没问题的话就应该可以出结果了:hello4
可能出现的⼀些问题:
1:使⽤g++编译和gcc编译c和cpp⽂件⽣成动态链接库时可能会出现⼀些格式不符合的问题,⽐如
Exception in thread “main” java.lang.NoClassDefFoundError: Hell
因此,如果使⽤gcc编译没通过,你可以使⽤g++⽣成
2:完成上⾯步骤后报错:
Exception in thread “main” java.lang.UnsatisfiedLinkError: /usr/lib/libA.so: /usr/lib/libA.so: undefined symbol:
_ZN5TwoNoC1Eii
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1751)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1647)
at java.lang.Runtime.load0(Runtime.java:769)
at java.lang.System.load(System.java:968)
at Add.(Add.java:5)
该错误应该是⽣成libA.so时没有包含它所需要的动态连接库libTwono,因此在g++ -I/java/jdk1.5.0_08/include -L/usr/lib -shared -o Add.cpp -lTwono
最后⼀定要包含-lTwono(即它所需要的库)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。