[转载] C++转JAVA的转换方法及约定

参考链接: C++和Java中的Foreach

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中的函数来实现,即Par3为Part1和Part2提供服务,而Part3通过JNI调用本地方法  public class JA { //Part 1 construct与finallize,必须提供=================================================         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提供本类供part1和part2中方法调用的本地代码的声明注意本部分不对//外暴露任何东西,命名的方法是在 part1和part2暴露方法的的名字前加一个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 construct与finallize        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 提供本类供part1和part2中方法调用的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、付费专栏及课程。

余额充值