2013-10-01 130 views
7

我有一個簡單的java類(「MainX」),我使用shell腳本和eclipse編譯。當我調用env-> FindClass(「MainX」)函數時,從該腳本生成的MainX.class文件返回null,而從eclipse生成的MainX.class文件返回該類並在其後執行runMainX函數。JNI-FindClass函數返回null

生成的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 

.... 
.... 
} 

有人能解釋我爲什麼出現這種情況?

我很感激任何幫助。

任何想法???在此先感謝

回答

15

JNI DocumentationFindClass

 
name: a fully-qualified class name (that is, a package name, delimited by "/", 
     followed by the class name). 

所以假設類是在包your.package.name,我想你將不得不更換

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

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

Hope這有助於!

+0

謝謝mbrenon。但是,我沒有任何包裹。它在我看到的src目錄 – STiGMa

+0

中。不知道然後,我習慣於在Android上下文中使用JNI,其中包是強制性的,據我所知... – mbrenon

13

我不確定您的平臺上存在這個問題,但我在Android平臺上遇到類似問題。

只應從Java線程調用FindClass方法。 FindClass的實現通過遍歷當前的調用棧來查找ClassLoader。由於您試圖從本地線程調用FindClass,因此沒有ClassLoader可供查找。 看看這個JNI FAQ

如果類名看起來正確,你可以運行在一個類加載器 問題。 FindClass想要在與您的代碼相關的類 加載器中啓動類搜索。它檢查調用堆棧,這 看起來像:

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

最上面的方法是Foo.myfunc。 FindClass查找與Foo類關聯的ClassLoader對象 並使用它。

+0

有關完整的代碼解決方案,請參閱http://stackoverflow.com/a/16302771/1046167及其評論。 –

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/ 

我希望它能幫助!