持有JNI中本机类对象的引用
Holding reference to native class object in JNI
我正在尝试创建一个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
也得到堆错误弹出后,这段代码执行
好,下面是第一眼看到的问题列表:
-
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位平台上都可以正常工作。
#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;
}
相关文章:
- 返回常量对象引用 (getter) 和仅返回字符串有什么区别?
- 我们可以有一个 setter 成员函数作为从 const 对象引用的 const 吗?
- C++对象引用返回不同的值
- 对象引用中的字段以不同的方法返回不同的值
- 通过向构造函数其他对象引用页面来创建对象
- 为什么在对象引用恒定时允许更改为另一个类的指针的成员变量
- 如何在C++中读取 HDF5 对象引用
- C++ 未定义的对象引用
- 从函数返回 libconfig 类设置对象引用
- qt vsaddin错误对象引用未设置为对象的istanse
- 在这种情况下,为什么使用 *此必需的对象引用返回对象引用
- 基本C - 构造contaning对象引用,并将其作为方法参数传递
- C :将对象引用作为参数给出错误:呼叫class :: function()的匹配函数
- C++OOP基础知识-是否正确返回对象引用
- 使用对象引用(可能)在调用destructor后使用对象引用
- 创建返回对象引用的成员函数的最简单方法
- 如何在C++上使用对象引用删除对象
- JNI/Android NDK-维护全局对象引用
- 为什么有些类方法返回"*this"(self的对象引用)?
- 在C++中返回伪对象引用的规则