13

我有一个简单的 java 类(“MainX”),我使用 shell 脚本和 eclipse 编译它。当我调用 env->FindClass("MainX") 函数时,从脚本生成的 MainX.class 文件返回 null 而从 eclipse 生成的 MainX.class 文件返回该类,然后执行 runMainX 函数。

生成的 MainX.class 文件与 JNI C++ 可执行文件位于同一文件夹中。

MainX.java

public class MainX {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println(new MainX().runMainX());
    }

    public String runMainX(){
        return ("0.789");
    }
}

JNIBinding.cpp

#define USER_CLASSPATH "."
....
....

JNIEnv* createVM (JavaVM **jvm)
{
    JNIEnv *env;                     /* pointer to native method interface */
    JavaVMInitArgs vm_args;              /* JDK/JRE 6 VM initialization arguments */
    JavaVMOption* options = new JavaVMOption[1]; //holds various JVM optional settings

    options[0].optionString = const_cast<char*>("-Djava.class.path="USER_CLASSPATH);
    vm_args.version = JNI_VERSION_1_6;       //version of Java platform
    vm_args.nOptions = 1;
    vm_args.options = options;
    vm_args.ignoreUnrecognized = false;
    /* load and initialize a Java VM, return a JNI interface * pointer in env */
    long status = JNI_CreateJavaVM(jvm, (void**)&env, &vm_args);

    if (status == JNI_ERR){
       cout << "Fail: Unable to load JVM \t Exit" << endl;
    }
    else if (status == JNI_OK){
    cout << "CreateVM:\t\tJVM loaded successfully!" << endl ;
    }

    delete options;
    return env;
}

....
....

float invokeMainX(JavaVM **jvm, JNIEnv *env){

    jclass    mainClass ; //Returns a class object from a fully-qualified name, or NULL if the class cannot be found.
    jmethodID classConstructor; //Returns the method ID for an instance (nonstatic) method of a class 
    jobject   classObject;  //Constructs a new java object
    jmethodID methodid;

    float outcome = 0;

    mainClass = env->FindClass("MainX");    //Returns a class object from a fully-qualified name, or NULL if the class cannot be found.
    if (mainClass==0) return 0;
         classConstructor = env->GetMethodID(mainClass, "<init>", "()V"); //Returns the method ID for an instance (nonstatic) method of a class 
    if (classConstructor==0) return -1;  
         classObject = env->NewObject(mainClass, classConstructor); //Constructs a new java object
    if (classObject==0) return -2;  
         methodid = env->GetMethodID(mainClass, "runMainX", "()Ljava/lang/String;");
    if (methodid==0) return -3;
            jstring result = (jstring)env->CallObjectMethod(classObject, methodid); //returns the result of the calling method, an object 

....
....
}

有人可以解释一下为什么会这样吗?

我很感激任何帮助。

任何的想法???提前致谢

4

3 回答 3

25

来自JNI文档FindClass

name:完全限定的类名(即包名,用“/”分隔,
      后跟类名)。

因此,假设该类在包your.package.name中,我想您将不得不替换

mainClass = env->FindClass("MainX");

mainClass = env->FindClass("your/package/name/MainX");

希望这可以帮助!

于 2013-10-01T12:37:01.630 回答
16

我不确定您平台上的这个问题,但我在 Android 平台上遇到了类似的问题。

FindClass 方法只能从 Java 线程调用。FindClass 的实现是通过遍历当前调用栈来寻找一个 ClassLoader。由于您试图从本机线程调用 FindClass,因此没有要查找的 ClassLoader。看看这个JNI 常见问题解答

如果类名看起来正确,您可能会遇到类加载器问题。FindClass 想要在与您的代码关联的类加载器中开始类搜索。它检查调用堆栈,看起来像:

Foo.myfunc(Native Method)
Foo.main(Foo.java:10)
dalvik.system.NativeStart.main(Native Method)

最顶层的方法是 Foo.myfunc。FindClass 找到与 Foo 类关联的 ClassLoader 对象并使用它。

于 2013-12-30T16:21:55.237 回答
0

我有 CentOS 6 x86_64,直到我修改了这些行,它才起作用:

vm_args.version = JNI_VERSION_1_4;
...
options[0].optionString = (char *)"-Djava.class.path=/home/oscar/Projects/Java-C++";

我还需要导出 LD_LIBRARY_PATH:

javac HelloWorldApp.java Bicycle.java
g++ Prueba2.cpp -o Prueba2 -L/usr/lib64/gcj-4.4.4 -ljvm
export LD_LIBRARY_PATH=/usr/lib64/gcj-4.4.4/

我希望它有帮助!

于 2014-03-13T07:46:05.250 回答