在JNI中保持对本机类对象的引用

时间:2014-03-22 18:26:30

标签: java c++ java-native-interface

我正在尝试创建一个c ++类并将其对象保存到一个数组中,并使用JNI从java引用那些c ++对象,因为JNI没有提供任何机制来将任何非原始类型的对象保存到java中。

我已经实现了下面提到的代码,但是输出显示我好像创建了多个对象,并且我在第二次调用时也收到堆错误以创建新的本机对象。

任何人都可以看一下吗?

感谢

代码:

Java类(加载库dll的函数已在LibObj中定义):

package org.jnp.pkg004;

import org.jnp.libloader.LibObj;

public class PureCppObjFactory extends LibObj {

    private long cppobjlstsz;

    public PureCppObjFactory() {
        super();
        cppobjlstsz=0;
    }

    public native void newCppObj();

    public native void PrintCppObjDetails(long cppobjlstindex);

}

C ++库代码:

#include "stdafx.h"
#include "stdlib.h"
#include <iostream>
#include <iomanip>
#include <stdio.h>

using namespace std;

#include "org_jnp_pkg004_PureCppObjFactory.h"

class NativeObjClass
{
    private:
        int num_ran;
        int obj_num;
    public:
        static int obj_cnt;
        NativeObjClass()
        {
            obj_cnt++;
            obj_num=obj_cnt;
            num_ran=rand();
            cout<<"Native Object number "<<setfill('0')<<setw(5)<<obj_cnt<<" Random number:"<<num_ran<<endl;    
        }

        int get_obj_num()
        {
            return obj_num;
        }

        int get_num_ran()
        {
            return num_ran;
        }
};

int NativeObjClass::obj_cnt=0;

NativeObjClass *nobj_lst;
long nobj_lst_size=0;

JNIEXPORT void JNICALL Java_org_jnp_pkg004_PureCppObjFactory_newCppObj
  (JNIEnv *env, jobject obj)
{

    jclass thisCls = env->GetObjectClass(obj);
    jfieldID fid=env->GetFieldID(thisCls,"cppobjlstsz","J");    
    NativeObjClass nobj;

    jlong java_lst_sz=env->GetLongField(obj,fid);   

    NativeObjClass *temp_nobj_lst;
    temp_nobj_lst=new NativeObjClass[nobj_lst_size];
    if(nobj_lst_size>0)
    {
        memmove(temp_nobj_lst,nobj_lst,nobj_lst_size);
        delete nobj_lst;
    }   
    nobj_lst_size++;
    nobj_lst=new NativeObjClass[nobj_lst_size];
    if(nobj_lst_size>1)
    {
        memmove(nobj_lst,temp_nobj_lst,nobj_lst_size);
        delete temp_nobj_lst;
    }
    nobj_lst[nobj_lst_size]=nobj;
    java_lst_sz++;

    env->SetLongField(obj,fid,java_lst_sz);

}


JNIEXPORT void JNICALL Java_org_jnp_pkg004_PureCppObjFactory_PrintCppObjDetails
  (JNIEnv *env, jobject obj, jlong indx)
{
    NativeObjClass nobj=nobj_lst[indx];
    cout<<"Retrieved Native Object number "<<setfill('0')<<setw(5)<<nobj.get_obj_num()<<" Random number:"<<nobj.get_num_ran()<<endl;
}

包含main的类:

package test.jnp.pkg004;

import org.jnp.pkg004.PureCppObjFactory;

public class PureCppObjFactoryTest {

    public static void main(String[] args) {

        PureCppObjFactory pcf=new PureCppObjFactory();
        pcf.newCppObj();
        pcf.PrintCppObjDetails(0);
        pcf.newCppObj();
        //pcf.newCppObj();

    }

}

输出:

Native Object number 00001 Random number:41
Native Object number 00002 Random number:18467
Retrieved Native Object number 00002 Random number:18467
Native Object number 00003 Random number:6334
Native Object number 00004 Random number:26500

此代码执行后也会弹出堆错误

2 个答案:

答案 0 :(得分:3)

好的,这是乍看之下的问题清单:

  • using namespace std;表格不好
  • static int obj_cnt;不是线程安全
  • NativeObjClass *nobj_lst;应该是静态成员
  • NativeObjClass *nobj_lst;应该是std :: vector
  • long nobj_lst_size=0;应该是静态成员
  • long nobj_lst_size=0;应为size_t
  • 类型
  • NativeObjClass nobj;创建了一个对象 - 它不仅仅是一个参考
  • nobj_lst=(NativeObjClass*)calloc(nobj_lst_size,sizeof(NativeObjClass));完全错了。如果您必须使用手动管理的阵列,请使用new[],但std::vector仍然会更好
  • nobj_lst[nobj_lst_size-1]=nobj复制您创建的对象
  • NativeObjClass nobj=nobj_lst[indx];制作数组对象的无意义副本

请考虑这种方法。请注意,以下代码尚未经过测试或编译,只是为了显示这个想法。

public class CppObject {

    private long handle;

    public CppObject() {
        handle = createNativeObject();
    }

    public void cleanup() {
        deleteNativeObject(handle);
        handle = 0;
    }

    private static native long createNativeObject();
    private static native void deleteNativeObject(long handle);
    private static native void printObjectDetails(long handle);


    public void PrintObjDetails() {
        printObjectDetails(handle);
    }

}




JNIEXPORT jlong JNICALL whatever_createNativeObject(JNIEnv *env, jobject obj) {
    return reinterpret_cast<jlong>(new CppObject());
}

JNIEXPORT void JNICALL whatever_deleteNativeObject(JNIEnv *env, jobject obj, jlong handle) {
    delete reinterpret_cast<CppObject *>(handle);
}

JNIEXPORT void JNICALL printObjectDetails(JNIEnv *env, jobject obj, jlong handle) {
    reinterpret_cast<CppObject *>(handle)->printDetails();
}

java long是64位,因此上述代码在32位和64位平台上都可以正常工作。

答案 1 :(得分:0)

#include "stdafx.h"
#include "stdlib.h"
#include <iostream>
#include <iomanip>
#include <stdio.h>

using namespace std;

#include "org_jnp_pkg004_PureCppObjFactory.h"

class NativeObjClass
{
    private:
        int num_ran;
        int obj_num;
    public:
        static int obj_cnt;
        NativeObjClass()
        {
            obj_cnt++;
            obj_num=obj_cnt;
            num_ran=rand();
            cout<<"Native Object number "<<setfill('0')<<setw(5)<<obj_cnt<<" Random number:"<<num_ran<<endl;    
        }

        int get_obj_num()
        {
            return obj_num;
        }

        int get_num_ran()
        {
            return num_ran;
        }
};

int NativeObjClass::obj_cnt=0;

NativeObjClass *nobj_lst;
long nobj_lst_size=0;

JNIEXPORT void JNICALL Java_org_jnp_pkg004_PureCppObjFactory_newCppObj
  (JNIEnv *env, jobject obj)
{

    jclass thisCls = env->GetObjectClass(obj);
    jfieldID fid=env->GetFieldID(thisCls,"cppobjlstsz","J");    
    NativeObjClass nobj;    

    jlong java_lst_sz=env->GetLongField(obj,fid);       

    if(nobj_lst_size==0)
    {           
        nobj_lst_size++;
        nobj_lst=(NativeObjClass*)calloc(nobj_lst_size,sizeof(NativeObjClass));     
        nobj_lst[nobj_lst_size-1]=nobj;
    }   
    else
    {
        nobj_lst_size++;
        nobj_lst=(NativeObjClass*)realloc(nobj_lst,nobj_lst_size*sizeof(NativeObjClass));   
        nobj_lst[nobj_lst_size-1]=nobj;
    }   

    java_lst_sz++;
    env->SetLongField(obj,fid,java_lst_sz);

}


JNIEXPORT void JNICALL Java_org_jnp_pkg004_PureCppObjFactory_printCppObjDetails
  (JNIEnv *env, jobject obj, jlong indx)
{
    NativeObjClass nobj=nobj_lst[indx];
    cout<<"Retrieved Native Object number "<<setfill('0')<<setw(5)<<nobj.get_obj_num()<<" Random number:"<<nobj.get_num_ran()<<endl;
}