访问C++;使用JNI从Java获取对象数组
在我和的回答之后,我想以相反的方式尝试并强化前面的问题: 我想执行以下步骤:访问C++;使用JNI从Java获取对象数组,java,c++,java-native-interface,Java,C++,Java Native Interface,在我和的回答之后,我想以相反的方式尝试并强化前面的问题: 我想执行以下步骤: Java中的缓冲区分配 用C填充数组++ 在Java中编辑值 用C做一些数字运算++ 读取Java中的值 考虑C++中的以下类: #pragma once #pragma pack(push, 8) class Point { public: double x; double y; Point(); virtual ~Point(); void ebeProduct(Poin
#pragma once
#pragma pack(push, 8)
class Point
{
public:
double x;
double y;
Point();
virtual ~Point();
void ebeProduct(Point &other) {
x = x * other.x;
y = y * other.y;
}
};
Point::Point()
{
}
Point::~Point()
{
}
#pragma pack(pop)
以下代码段:
Point point = Point();
std::cout << "Size of Point: " << sizeof(Point) << std::endl;
std::cout << "Address is: " << &point << std::endl;
std::cout << "x address is: " << &(point.x) << " and offset is: " << (long long)&(point.x) - (long long)&point << std::endl;
std::cout << "y address is: " << &(point.y) << " and offset is: " << (long long)&(point.y) - (long long)&point << std::endl;
现在我可以假设Java中的以下大小:
final int NUMBER_OF_POINTS = 10;
final int SIZE_OF_POINT = 24;
final int X_OFFSET = 8;
final int Y_OFFSET = 16;
for (int i = 0; i < NUMBER_OF_POINTS; i++) {
System.err.print(unsafe.getDouble(address + i * SIZE_OF_POINT + X_OFFSET));
System.err.print(" ; ");
System.err.println(unsafe.getDouble(address + i * SIZE_OF_POINT + Y_OFFSET));
}
接下来,我将使用unsafe
分配一个内存区域,并调用公共静态本机void allocatePoints(长地址,int numberOfPoints)代码>以便用点
对象填充它们:
long address = unsafe.allocateMemory(NUMBER_OF_POINTS * SIZE_OF_POINT);
allocatePoints(address, NUMBER_OF_POINTS);
填充点的C++代码:
Point * points = (Point *) address;
for (int pointIndex = 0; pointIndex < numberOfPoints; pointIndex++) {
new(points + pointIndex) Point();
}
这些阶段实际上会打印正确的结果。
我的问题是,这些阶段是否合理:我能假定给定的偏移量是正确的(在同一台机器上),并且直接将值写入java中的缓冲区,并从C++中读取这些对象,总是会得到正确的结果吗? < P>我一般看到三个潜在的陷阱:
<> > > > >填充> VTABLE >代码>点>代码>可能会使大小< /强>:C++编译器可能决定将<代码>点>代码>成员对齐到它们想要的对齐(例如,A代码>双< /代码>要8字节对齐,而<代码> char < /C> >不指定任何对齐。
同样,如果C++对象包含任何<代码>虚拟< /COD>方法(如您的示例所示),则
对象的前面将有一个vtable。你需要考虑到这一点
分配内存和访问单个成员时的帐户
对齐点
可能会弄乱数组的步幅:假设类的最后一个元素有一个额外的字符
,那么下一个元素将对齐到8字节的最接近倍数。(换句话说,数组跨距为8+8+1(数据)+7字节填充)
在分配内存和访问单个成员时,都需要考虑这一点
sun.misc.Unsafe
即将退出。这段代码最终可能会停止在JDK11及更高版本中工作
1+2:关于对齐:我使用的是#pragma pack(16)
指令,它应该保证所有内容都对齐。3:如果Unsafe
将被弃用,并且没有其他方法分配大块内存,我将使用ByteBuffer。
for (int i = 0; i < NUMBER_OF_POINTS; i++) {
unsafe.putDouble(address + i * SIZE_OF_POINT + X_OFFSET, i);
unsafe.putDouble(address + i * SIZE_OF_POINT + Y_OFFSET, i * 2);
}
for (int i = 0; i < NUMBER_OF_POINTS; i++) {
System.err.print(unsafe.getDouble(address + i * SIZE_OF_POINT + X_OFFSET));
System.err.print(" ; ");
System.err.println(unsafe.getDouble(address + i * SIZE_OF_POINT + Y_OFFSET));
}