从Java调用C ++函数

时间:2016-12-05 08:28:36

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

这是我在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();
};

1 个答案:

答案 0 :(得分:3)

你不能直接调用这样的函数,你将从JNI调用的函数必须具有特定的名称和特定的形式,并且必须由某个Java类中的成员函数表示。 (此外,Java没有无符号整数,因此您的uint8_t可能必须是char或其他一些原始类型,同样您需要考虑代表std::vector的内容在Java中。)但是完全可以

  1. 使Java函数可公开访问(不幸的是,它不能是静态的,类实例很重要),

  2. 让本机实现只提取参数并调用accessZ()

  3. 通常,您的代码看起来像

    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)