2015-04-23 9 views
7

Iniziare a utilizzare JNI per richiamare metodi java statici da C++. In particolare, dopo aver ottenuto un jclass (utilizzando FindClass) e un jmethodID (utilizzando GetStaticMethodID), ho proceduto a chiamare la serie di routine CallStatic * MethodA. Risulta che tutte queste routine prendono un jclass come primo parametro. Ho iniziato a chiedermi perché è necessario l'oggetto classe: poiché tutte le informazioni sono state fornite in GetStaticMethodID, l'oggetto classe non sembra necessario affinché JVM possa svolgere il lavoro. Ho quindi provato a chiamare queste routine passando NULL per il primo parametro e l'invocazione è riuscita.JNI Richiamo dei metodi statici. L'oggetto di classe è necessario?

La mia domanda: è sicuro chiamare questi metodi con un oggetto di classe NULL?

L'incentivo è: se è effettivamente legale, non dovrò memorizzare nella cache l'oggetto di classe per le chiamate successive ai metodi statici (ricordando di chiamare NewGlobalRef ....). La memorizzazione nella cache di jmethodID sarebbe sufficiente.

+1

Dalvik [non utilizza il parametro jclass] (https://android.googlesource.com/platform/dalvik.git/+/android-4.2.2_r1/vm/Jni.cpp) in 'CallStatiC## _ jname ## Method', quindi appare come se passare 'NULL' sarebbe ok. Tuttavia non posso dire nulla di altre JVM. – Michael

+1

La specifica JNI dice che è necessario, quindi è necessario. Non scriverei codice che dipende da una stranezza di una JVM specifica. – EJP

+0

Funziona solo perché il metodo statico non chiama altri metodi statici della stessa classe, né utilizza variabili di classe statiche! – Christophe

risposta

2

No, è assolutamente non sicuro chiamare tale funzione statica con un puntatore di classe null (o non valido).

La tua pratica può benissimo succedere, per esempio se il tuo metodo statico non si riferisce a nessun altro membro di classe statico. Tuttavia, se il metodo java statico si riferisce a qualsiasi altro membro statico, la tua JVM avrà bisogno del puntatore di classe valido.

Esempio:

prendere questa semplice Java demo MyTest.java:

public class MyTest { 
    public static void mymain() { 
     System.out.println("Hello, World in java from mymain"); 
     System.out.println(magic_counter); // this will cause a segfault if 
    }          // class pointer is null 
    private static int magic_counter=777; 
} 

e chiamarlo con il seguente JNI C++ snippet

... // JVM already loaded and initialised 

jclass cls2 = env->FindClass("MyTest"); 
if(cls2 == nullptr) { 
    cerr << "ERROR: class not found !"; 
} 
else { 
    cout << "Class MyTest found" << endl; 
    jmethodID mid = env->GetStaticMethodID(cls2, "mymain", "()V"); 
    if(mid == nullptr) 
     cerr << "ERROR: method void mymain() not found !" << endl; 
    else { 
     env->CallStaticVoidMethod(cls2, mid); 
     cout << endl; 
    } 
} 

Calling GetStaticMethodID(nullptr, "mymain", "()V"); fallirebbe. Perché quando si esegue mymain(), proverà ad accedere alla variabile statica magic_number. La JVM utilizzerà quindi il puntatore di classe che hai fornito e assumerà che sia un puntatore vaild restituito da una classe caricata. Ma dato che è nullo, il sistema segfault.

+0

Ho provato il tuo esempio e non esiste un segfault. Sto usando Oracle jdk/jre 1.8.0.45 su linux per java e g ++ per compilare il C++. Cosa JVM stai usando e su quale sistema operativo? BTW, mi manca qualcosa ... trovo difficile capire che una volta che i confini nativi/JAVA sono stati attraversati e il codice JAVA è stato eseguito, la JVM - in fase di esecuzione - deve ancora ricorrere alla classe oggetto passato nel lato C++ del confine per la risoluzione di membri/metodi static nidificati ... – user4212919

+0

solo per essere sicuri ... Sto passando NULL a CallStaticVoidMethod (NULL, mid), non a GetStaticMethodID (cls2, "mymain", "() V") ... – user4212919

+0

@ user4212919 beh, ho la stessa versione java, in esecuzione in modalità 64 bit, ma su Windows 8.1 con MSVC2013. Potrei eseguire questo esempio con NULL invece di cls2 se e solo se commento la stampa di magic_number. – Christophe