无法使用 JNI 使用外部 Java 类

Posted

技术标签:

【中文标题】无法使用 JNI 使用外部 Java 类【英文标题】:Can't use external Java class using JNI 【发布时间】:2014-12-07 17:56:52 【问题描述】:

我在通过 JNI 使用外部 Java 类时遇到问题。我会用一个玩具例子来说明我的问题。

这是我的 Java 类,作为一个例子,它使用了 Apache Commons IO 的外部类 FilenameUtils:

Example.java

import org.apache.commons.io.FilenameUtils;

class Example 

    static void base () 

        String str = "/usr/foo.bar";
        System.out.println("Before");
        try 
            System.out.println(FilenameUtils.getBaseName(str));
        
        catch (Exception e) 
            System.out.println(e.getMessage());
        
        System.out.println("After");
    

    public static void main(String[] args) 
        base();
       

我的类路径是用 $CLASSPATH 设置的:

export CLASSPATH=".:/Applications/eclipse/plugins/*"

我用javac编译,然后执行。这是我得到的输出,是正确的:

之前 富 之后

当我使用 JNI 从 C++ 调用 Java 方法“base”时,问题就出现了。这是 C++ 代码:

test.cpp

#include <jni.h>
#include <cstring>

int main()

    JavaVMOption options[1]; 
    JNIEnv *env;
    JavaVM *jvm;
    JavaVMInitArgs vm_args; 
    jclass cls;
    jmethodID method;
    jobject simpleJNITestInstance;

    options[0].optionString = "-Djava.class.path=.:/Applications/eclipse/plugins/*";
    memset(&vm_args, 0, sizeof(vm_args));
    vm_args.version = JNI_VERSION_1_6;
    vm_args.nOptions = 1;
    vm_args.options = options;

    long status = JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args);
    if (status != JNI_ERR)
    
        cls = env->FindClass("Example");
        if (cls != 0)
        
            method = env->GetStaticMethodID(cls, "base", "()V");
            env->CallStaticVoidMethod(cls, method, 5);
        
        jvm->DestroyJavaVM();
    
    printf("Finished\n");
    return 0;

虽然我认为在我的情况下没有必要,因为它已经配置了 $CLASSPATH,但我再次在 VM 选项中指定了类路径。我还在 CallStaticVoidMethod 函数中添加了参数 5,因为我不知道如何指定零参数。 Java 方法不接收任何参数,因此将被忽略。

然后我编译这个 C++ 代码:

g++  -o test \
 -I/Library/Java/JavaVirtualMachines/jdk1.7.0_72.jdk/Contents/Home/include \
 -I/Library/Java/JavaVirtualMachines/jdk1.7.0_72.jdk/Contents/Home/include/darwin \
 -L/Library/Java/JavaVirtualMachines/jdk1.7.0_72.jdk/Contents/Home/jre/lib/server/ \
 test.cpp \
 -ljvm

并执行这个编译好的程序。这是我现在得到的输出:

之前 完成了

方法“base”的执行只是在它访问 getBaseName 方法时停止。不会引发异常,它只是停止执行,并返回到本机代码。

为什么FilenameUtils.getBaseName()方法无法执行?

我的机器运行的是 Mac OS 10.10 Yosemite,Java 1.7.0.72 64 位。

提前致谢。

更新

我尝试将 commons-io-2.4.jar 直接包含在类路径中,现在程序可以运行了:

    options[0].optionString = "-Djava.class.path=.:/Applications/eclipse/plugins/commons-io-2.4/commons-io-2.4.jar";

现在我的问题是,为什么使用 JNI 时类路径的行为会有所不同?

【问题讨论】:

【参考方案1】:

所以问题很简单。使用 $CLASSPATH 或 -cp 指定类路径时,可以使用通配符。

但是如果使用“-Djava.class.path”通配符设置类路径不起作用,则必须单独指定jar和目录列表。

此外,“-Djava.class.path”会覆盖 $CLASSPATH。

【讨论】:

以上是关于无法使用 JNI 使用外部 Java 类的主要内容,如果未能解决你的问题,请参考以下文章

使用在C ++中导入外部jar文件的java类

JNI——Android Native中跨线程使用JNI的问题

无法从 JNI 设置 Java int 数组字段

Android使用JNI,C++调用JAVA代码,能找到JAVA的函数无法调用?

JNI 无法在 NetBeans 上检测到 __int64

01_JNI是什么,为什么使用,怎么用JNI,Cygwin环境变量配置,NDK案例(使用Java调用C代码),javah命令使用