jni中 对c++类的重新封装

前段时间用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 libTwono.so Twono.cpp
第二步:
为了能在java中使用类TwoNo中的Add方法,我现在Add.java中来声明native函数add(),add()函数封装了类Twono中的Add方法,native限定词是实现jni本地调用的关键字,说明了该方法是需要通过其他语言来实现的。
//Add.java
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.cpp 封装类Twono中的Add()
//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
#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 libA.so 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.<clinit>(Add.java:5)

该错误应该是生成libA.so时没有包含它所需要的动态连接库libTwono,因此在g++ -I/java/jdk1.5.0_08/include -L/usr/lib -shared -o libA.so Add.cpp -lTwono
最后一定要包含-lTwono(即它所需要的库)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值