C++转JAVA的转换方法及约定

6 篇文章 0 订阅
3 篇文章 0 订阅

1.基本思想:

1.1 使对象对应

每出现一个C++类就写一个JAVA类, JAVA类的行为完全模仿C++类的行为. 而且要保证C++的对象的生存期至少比JAVA长, 而且能够保证使所有动态分配出来的C++对象有机会得到析构。

 

实现的方法是在每个JAVA类中添加一个int 类型的变量 ptr(参见表2.1中的part4),ptr指向该JAVA类所对应的C++对象。ptr并不在JAVA中使用,它只在本地方法中通过转换成相应的C++对象,来实现对C++调用(请参考表3.1 示例)。

 

1.2 关于C++对象和JAVA对象的生存期问题的解决:

对于C++对象的生成有两种情况

1.2.1第一种情况,新的C++对象在原C++系统内部管理,在JAVA中我们不关心它的创建和释放

C++对象是由原系统(C++)内部生成,然后返回给外部调用最后再由原C++系统释放。在这种情况下,我们新建一个对应的JAVA类,然后把这个C++对象的地址赋给该JAVA类的内部成员变量ptr(通过带有参数(FromReturn ,int exestPtr)的构造函数实现,其中FromReturn是一个空类用于标注不要创建C++对象,参见表2.1)。

按目前的分析,这种情况仅限于在原系统中返回值是C++指针的情况

1.2.2第二种情况,新的C++对象在外部创建

是除第一种情况之外的(动态创建和静态创建都包括)其它所有情况

(1)若原C++类提供了构造函数,则在相应的JAVA类中效仿C++中的构造函数将它改造成JAVA格式。然后在此JAVA构造函数中调用Part3中的服务接口函数,该服务接口函数(JNI)在相应的本地方法中创建新的C++对象(并将它放进全局的对象管理类, 见本条末)。 在finallize的接口服务函数(JNI)的本地方法中释放这个C++对象,但是JAVA并不保证finallize一定执行,我们通过在JNI的本地实现中声明一个全局的对象管理类来解决,当新分配一个C++对象时我们把它放进这个管理类,当finallize 执行时我们告诉这个管理类让它释放掉这个类。最后我们在这个管理类的析构函数中释放掉所有未能被释放的C++对象。(该类参见表2.2CObjectManager类)

(2)若原C++类提没有供了构造函数则我们在JAVA端提供一个空参数的构造函数(示例3.1中的JA),其余同(1)

注:每个JAVA类都有4个部分Part1, Part2, P art3, Part4

1.3 关于关于多态问题的解决:

当C++中的函数返回类型为基类类型的指针而实际返回的是C++子类的对象时,相应的转到JAVA后也要返回的是JAVA基类类型但是要返回实际的JAVA子类对象,这时需要在C++端的基类中提供一个GetType函数在JAVA端根据不同的类型返回不同的JAVA子对象

 

2.约定

2.1类名

JAVA系统内类名与C++类的类名一致,方法格式一致

2.2关于类的创建:

参见1.2

2.3每个JAVA类都有四个部分.如表2.1所示。(此处以类JA为例)

其中用到一个全局的类

public class FromReturn(){}

是一个空类,用在传给JAVA类的构造函数的参数,用于标注不要在构造函数中创建C++对象。这种情况适用于在原C++系统中返回一个类的情况。

 


 

表2.1对JAVA类的约定

对JAVA类的约定(以类JA为例),共分四个部分Parts1 Part2中的方法除 JA(FromReturn ,int exestPtr)这个构造函数外,其余的函数都要在Part3中的函数来实现,即Par3Part1Part2提供服务,而Part3通过JNI调用本地方法

public class JA {

//Part 1 constructfinallize,必须提供=================================================

        protected  JA(FromReturn ,int exestPtr){//所有的类必须提供这个构造方法,除了类名不一样外其余部分完

              ptr =existPtr;                       //全一样这个构造函数并不需要JNI,仅供内部使用,除这个构造函数外其

              isFromReturn=true;      //它在本部分的方法都需要JNI,该方法内容十分固定,所有类必须遵守

       }                                              

 

       public JA(){ptr=nJA(); isFromReturn =false;}//

        public  synchronized  finalize(){if(! isFromReturn )nfinallize(ptr);}

//Part 2必须提供,与c++中暴露的方法一至,但要对应到JAVA格式========================

       public SomeClass SomeMethod(){//有返回,对象类型

               int ptrB;

ptrB = nSomeMethod (ptr);

SomeClass b=SomeClass (new FromReturn(), ptrB);

Return b;

       }

 

       public int SomeMethod2(){return  nSomeMethod2( ptr);  }//有返回,基本类型(以int为例)

       public void SomeMethod3(){ nSomeMethod3( ptr); }//无返回

       //以上几个示例函数只是针对在原C++系统中没有传入参数的情况,对于在原C++系统中有传入参数的情

       //,根据JNI的特性直接传即可。只是对在原C++系统中传入的参数是基本类型的引用或是基本类型的指针      //指针的情况有所不同(因为这些参数有可能被改变),解决的办法是将每个参数放进容量等于1的数组里       //再传

//Part 3访问权限一至protected native提供本类供part1part2中方法调用的本地代码的声明注意本部分不对//外暴露任何东西,命名的方法是在 part1part2暴露方法的的名字前加一个n,当返回的是对象或结构时,//要返回它的在C++中的指针,在JAVA端用int表示。每个方法声明的第一个参数都是一至的,都本类的prt属性(服务于构造函数的JNI声明除外——在本地端动态获得这个ptr,并把新分配的C++对象指针赋于它)

//===========================================================================

       //针对part1

       private native int nJA();//注:这里没有传入ptr,返回的值被赋给ptr。在本地C++nJA new一个新的C++                            //对象,并将其指针放入CObjectManager

       private native void nfinallize(int ptr);

       //针对 part2 ,part2中有什么样的函数这里就有相对应的服务函数声明

       private native int           nSomeMethod (int ptr );//有返回,对象类型

       private native int           nSomeMethod2 (int ptr );//有返回,基本类型(以int为例)

       private native void         nSomeMethod3 (int ptr );//无返回

//Part 4 =================================================

    publicintptr;//指向对应的C++对象的指针

    privatebooleanisFromReturn;//参见第4部分修改说明

 

}

 表2.2本地全局管理类CObjectManager


 

CObjectManager

//注:在真实环境下使用时,Add方法要包含类的信息,在析构时也要根据类的信息把VOID*类型强制转换成目标类型后再析构

class  CObjectManager{

public:

       Add(void * cppObj);//添加类地址到objs

       Remove(void* cppObj);//释放cppObj对象,并将其在objs中移除

       CObjectManager();//构造函数,初始化objs

       ~ CObjectManager();//析构函数,若objs不空,则释放objs中的所有对象,并将objs清空

private:

       map<int , void*>objs;//键和值为同一值

}

 







3 示例


 

表3.1. 示例

JAVA

JNI

C++

public class JA {

//Part 1 constructfinallize

       protected JA(FromReturn,int exestPtr){

              ptr =existPtr;

              isFromReturn=true;

       }

       public JA(){

              ptr=nJA();

              isFromReturn=false;

       }//

       Public synchronized finalize()

       {if(!isFromReturn)nfinallize(ptr);}

//Part 2 必须提供,与c++中暴露的方法一至,但要对应到JAVA格式

       public JB GetB(){

             

              int ptrB;

              ptrB=nGetB(ptr);

              JB b=new JB(new FromReturn(),ptrB);

              return b;

       }

//Part 3访问权限一至protected native

提供本类供part1part2中方法调用的JNI的声明注意本部分不对外暴露任何东西

       //针对part1

       private native int  nJA();

       private native void nfinallize(int ptr);

       //针对 part2

       private native int nGetB(ptr);

//Part 4 指向对应的C++对象的指针

       protected int   ptr;

       privatebooleanisFromReturn;

}

extern CObjectManager g_om;

 

JNIEXPORT void JNICALL Java_mypack_myTest_ nGetB

  (JNIEnv * env, jobject obj,jint jPtr )

{

    A* ptrA=(A*)jPtr;

    B* ptrB=ptrA->GetB();

    return (int)ptrB;

}

//如果返回的B对象不是指针类型而是对象本身(在右边一栏的函数声明类似这样B GetB();)则以上函数中的代码应如下所示

       A* ptrA=(A*)jPtr;

       B *ptrB=new B();

       (*ptrB) = ptrA ->GetB();

       g_om.Add(ptrB);

       return (int)ptrB;           

//nfinallize要做如下实现

JNIEXPORT void JNICALL Java_mypack_myTest_ nfinallize

  (JNIEnv * env, jobject obj,jint jPtr )

{

       g_om.Remove(jPtr);

}

 

//其它函数略

 

  .h文件

class A{

public:

       B* GetB();

};

.cpp文件

B* A::GetB()

{

       return new B();

}//这个地方新分配了一个对象而且返回了它的指针,我们在JAVA调用的时候不必关心它的释放问题,因为只要我们JAVA端完全仿效C++运行流程的话,C++系统会在自己内部释放该对象

public class JB {

//Part 1

//略

//Part 2

public void TestB(){

       nTestB(ptr);

}

//Part 3

private native void nTestB(int ptr);

//其它略

//Part 4

protected int   ptr;

}

extern CObjectManager g_om;

 

JNIEXPORT void JNICALL Java_mypack_myTest_ nTestB

  (JNIEnv * env, jobject obj,jintjPtr)

{

    B* ptr=(B*)jPtr;

       ptr->TestB();

}

  .h文件

class B{

public:

void TestB();

};

//  .cpp文件

void B::TestB()

{

cout<<”this is B in C++”<<endl;

}

 

结果测试:

在JAVA中这样运行

假设原C++系统中这样运行

JB b=a.GetB();

b.TestB();

B* pb=a->GetB();//这个地方的”->”也可能是”.”

pb->TestB();

输出:

this is B in C++

this is B in C++

 

 

4 修改说明

1. 在每个JAVA类的PART4中添加 protected Boolean isFromReturn; 这个变量只在PART1中使用,而且在所有构造函数及finalize中使用。

2. finalize会存在同步问题。所以要加上synchronized

 

下面为一个例子

//  part1

    public CAnalyseRead(FromReturn obj,int exptr){

      

       ptr = exptr;  

       isFromReturn=true;

    }

    public CAnalyseRead(){

      

       ptr = nCAnalyseRead();

       isFromReturn=false;

    }

   

    publicsynchronizedvoid finalize(){

       //System.out.println("CAnalyseRead.finalize");

       if(!isFromReturn)

           nfinalize(ptr);

    }

//  part4

    publicintptr;

    privatebooleanisFromReturn;

 

 

乔成磊 qiaochenglei@163.com

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值