这是我在StackOverflow上的第一篇文章。我正在开展一个项目,我需要你在JNI的帮助。我被困在那里......我最近一直在阅读和尝试它,但仍然没有弄清楚如何让它发挥作用。
我在C ++中创建了一个静态库(伪代码如下所示):
// file: X.h
class X {
public:
X() {};
~X() {};
void fooX() { // do stuff };
void barX() { // do more stuff };
}
// file: X.cpp
#include "X.h";
// file: Y.h
#include "X.h"
class Y {
public:
Y() {x = new X()};
~Y() {};
fooY() { // do stuff };
barY() { // do more stuff };
private:
X x; // object of class X
}
// file: Y.cpp
#include "Y.h"
// file: Z.h
#include "Y.h"
class Z {
public:
Z(uint8_t, std::string, std::vector<uint8_t>);
~Z() {};
fooZ() { // do stuff };
barZ() { // do more stuff };
private:
Y y; // object of class Y
}
// file: Z.cpp
#include "Z.h"
Z::Z(uint8_t a, std::string b, std::vector<uint8_t> c)
{
/// do stuff and create an object of Y
Y y = new Y();
}
// file api.h
#include "Z.h"
void accessZ(uint8_t, std::string, std::vector<uint8_t>);
// file api.cpp
#include "api.h"
void accessZ(uint8_t a_uint,
std::string b_string,
std::vector<uint8_t> c_vector)
{
// create object of Z
Z z = new Z(a_uint, b_string, c_vector);
z->fooZ();
delete z;
z = NULL;
}
此外,我已将所有上述代码编译为C ++中的静态库(libXYZ.a)(使用MinGW在Windows 7上使用Eclipse C ++ CDT)。
现在,我希望能够从Java应用程序调用API accessZ() C ++函数! 换句话说,我已经用C ++实现了核心功能,我想用Java实现GUI。因此,我需要从Java GUI中访问C ++函数......
我该怎么做? 我需要直接答案而不是模糊的答案...
非常感谢您的帮助。
非常感谢您的支持。
被修改
我的项目如下:
MyLibrary
|
Makefile header/ source/ bin/ object/ lib/
X.h X.cpp X.o libXYZ.a
Y.h Y.cpp Y.o
Z.h Z.cpp Z.o
api.h api.cpp api.o
我需要的是能够使用 accessZ()函数将一些参数从Java传递到 libXYZ 。
新编辑:
public final class NativeClass {
{
System.loadLibrary("myLibrary");
}
public native void accessZ(char a_uint, String b_string, char[] c_vector);
public static final NativeClass getInstance() {
return INSTANCE;
}
private static final NativeClass INSTANCE = new NativeClass();
};
答案 0 :(得分:3)
你不能直接调用这样的函数,你将从JNI调用的函数必须具有特定的名称和特定的形式,并且必须由某个Java类中的成员函数表示。 (此外,Java没有无符号整数,因此您的uint8_t
可能必须是char
或其他一些原始类型,同样您需要考虑代表std::vector
的内容在Java中。)但是完全可以
使Java函数可公开访问(不幸的是,它不能是静态的,类实例很重要),
让本机实现只提取参数并调用accessZ()
。
通常,您的代码看起来像
public final class NativeClass {
{
System.loadLibrary("myLibrary");
}
public native void accessZ(char a_uint, String b_string, char[] c_vector);
public static final NativeClass getInstance {
return INSTANCE;
}
private static final NativeClass INSTANCE = new NativeClass();
};
然后,您的myLibrary.cpp
必须包含<jni.h>
和"api.h"
并包含一行
JNIEXPORT void JNICALL Java_NativeClass_accessZ(JNIEnv *env, jobject obj, jchar ja_uint, jstring jb_string, jcharArray jc_vector) {
uint8_t a_uint = (uint8_t)ja_uint;
const char *cfn = env->GetStringUTFChars(jb_string, 0);
std::string b_string{cfn};
env->ReleaseStringUTFChars(jb_string, cfn);
size_t sz = env->GetArrayLength(jc_vector);
std::vector<uint8_t> c_vector(sz);
jchar *c_array = env->GetCharArrayElements(jc_vector, NULL);
for(size_t i = 0; i < sz; i++)
c_vector[i] = c_array[i];
env->ReleaseCharArrayElements(jc_vector, c_array, 0);
accessZ(a_uint, b_string, c_vector);
}
包裹在extern "C"
块中。您的JNI教程将告诉您如何从中创建动态库并帮助Java找到它。只需在创建libXYZ.a
时静态链接项目的其他部分(.dll
)(即,在源中列出存档)。然后,您可以在Java中调用,例如:
NativeClass.INSTANCE.accessZ((char)10, "abc", new char[]{3, 5, 7});
此功能将成为您图书馆的访问点 ,但随后可以做任何想做的事情,它可以创建对象,调用它们的功能,它甚至可以保留瞬态,因为您的库将在调用之间保持运行。 (不过,对传递给函数的状态对象进行操作会更好。)可能会有任意多个函数库向Java公开这样的函数。
以下是我的命令行(适用于Linux):
g++ -isystem /usr/java/jdk1.8.0_101/include/ -isystem /usr/java/jdk1.8.0_101/include/linux myLibrary.cpp -c -fPIC
(creates myLibrary.o)
g++ myLibrary.o libXYZ.a -shared -o libmyLibrary.so
(creates libmyLibrary.so)