⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jniref.html

📁 jdbc书
💻 HTML
📖 第 1 页 / 共 3 页
字号:

<PRE>
<STRONG>Use the jobject argument:</STRONG>

  JNIEXPORT void JNICALL Java_ArrayHandler_returnArray
  (JNIEnv *env, jobject jobj){
  jclass cls=(*env)-&gt;GetObjectClass(env, jobj);
  }
</PRE>

or

<PRE>
<STRONG>Use the jclass argument:</STRONG>

  JNIEXPORT void JNICALL Java_ArrayHandler_returnArray
  (JNIEnv *env, jclass jcls){
  jclass cls=jcls;
  }
</PRE>

<H4>Retrieve a Method Identifier</H4>

Once the class has been obtained, the second step is to call 
the <CODE>GetMethodID</CODE> function to retrieve an identifier 
for a method you select in the class. The identifier is needed when calling 
the method of that class instance. Because the Java language supports
method overloading, you also need to specify the particular method 
signature you want to call. To find out what signature your Java 
language method uses, run the <CODE>javap</CODE> command as
follows:

<PRE>
  javap -s Class
</PRE>

The method signature used is displayed as a comment after each
method declaration as shown here:

<PRE>
bash# javap -s ArrayHandler
Compiled from ArrayHandler.java
public class ArrayHandler extends java.lang.Object {
  java.lang.String arrayResults[];
   /*   [Ljava/lang/String;   */
  static {};
   /*   ()V   */
  public ArrayHandler();
   /*   ()V   */
  public void displayArray();
   /*   ()V   */
  public static void main(java.lang.String[]);
   /*   ([Ljava/lang/String;)V   */
  public native void returnArray();
   /*   ()V   */
  public void sendArrayResults(java.lang.String[]);
   /*   ([Ljava/lang/String;)V   */
}
</PRE>


Use the <CODE>GetMethodID</CODE> function to call instance methods 
in an object instance, or use the <CODE>GetStaticMethodID</CODE> function
to call static method. Their argument lists are the same.

<H4>Call the Methods</H4>

Third, the matching instance method is called using a 
<CODE>Call&lt;type&gt;Method</CODE> function. The <CODE>type</CODE> value 
can be <CODE>Void</CODE>, <CODE>Object</CODE>, <CODE>Boolean</CODE>, 
<CODE>Byte</CODE>, <CODE>Char</CODE>, <CODE>Short</CODE>, <CODE>Int</CODE>, 
<CODE>Long</CODE>, <CODE>Float</CODE>, or <CODE>Double</CODE>. 

<P>
The parameters to the method can be passed as a comma-separated list, an 
array of values to the <CODE>Call&lt;type&gt;MethodA</CODE> function,
or as a <CODE>va_list</CODE>. The <CODE>va_list</CODE> is a construct often 
used for variable argument lists in C. <CODE>CallMethodV</CODE> is
the function used to pass a <CODE>va_list ()</CODE>. 

<P>
Static methods are called in a similar way except the method naming includes an 
additional Static identifier, <CODE>CallStaticByteMethodA</CODE>, and the 
<CODE>jclass</CODE> value is used instead of <CODE>jobject</CODE>.

<P>
The next example returns the object array by calling the
<CODE>sendArrayResults</CODE> method from the <CODE>ArrayHandler</CODE>
class.

<PRE>
// ArrayHandler.java
public class ArrayHandler {
  private String arrayResults[];
  int arraySize=-1;

  public native void returnArray();

  static{
    System.loadLibrary("nativelib");
  }
 
  public void sendArrayResults(String results[]) {
    arraySize=results.length;
    arrayResults=new String[arraySize];
    System.arraycopy(results,0,
                     arrayResults,0,arraySize);
  }

  public void displayArray() {
    for (int i=0; i&lt;arraySize; i++) {
      System.out.println("array element 
	"+i+ "= " + arrayResults[i]);
    }
  }

  public static void main(String args[]) {
    String ar[];
    ArrayHandler ah= new ArrayHandler();
    ah.returnArray();
    ah.displayArray();
  }
}
</PRE>

The native C++ code is defined as follows:

<PRE>
&#35;include &lt;jni.h&gt;
&#35;include &lt;iostream.h&gt;
&#35;include "ArrayHandler.h"

JNIEXPORT void JNICALL Java_ArrayHandler_returnArray
(JNIEnv *env, jobject jobj){

  jobjectArray ret;
  int i;
  jclass cls;
  jmethodID mid;

  char *message[5]= {"first", 
		"second", 
		"third", 
		"fourth", 
		"fifth"};

  ret=(jobjectArray)env-&gt;NewObjectArray(5,
      env-&gt;FindClass("java/lang/String"),
      env-&gt;NewStringUTF(""));

  for(i=0;i&lt;5;i++) {
    env-&gt;SetObjectArrayElement(
	ret,i,env-&gt;NewStringUTF(message[i]));
  }

  cls=env-&gt;GetObjectClass(jobj);
  mid=env-&gt;GetMethodID(cls, 
	"sendArrayResults", 
	"([Ljava/lang/String;)V");
  if (mid == 0) {
    cout &lt;&lt;Can't find method sendArrayResults";
    return;
  }

  env-&gt;ExceptionClear();
  env-&gt;CallVoidMethod(jobj, mid, ret);
  if(env-&gt;ExceptionOccurred()) {
    cout &lt;&lt; "error occured copying array back" &lt;&lt;endl;
    env-&gt;ExceptionDescribe();
    env-&gt;ExceptionClear();
  }
  return;
}
</PRE>

To build this on Linux, run the following commands:

<PRE>
  javac ArrayHandler.java
  javah -jni ArrayHandler

  g++  -o libnativelib.so 
	-shared -Wl,-soname,libnative.so
	-I/export/home/jdk1.2/include 
	-I/export/home/jdk1.2/include/linux nativelib.cc  
	-lc
</PRE>

If you want to specify a super class method; for example,
to call the parent constructor,
you can do so by calling the <CODE>CallNonvirtual&lt;type&gt;Method</CODE>
functions.

<P>
One important point when calling Java language methods or fields from
within native code is you need to catch any raised exceptions. The 
<CODE>ExceptionClear</CODE> function clears any pending
exceptions while the <CODE>ExceptionOccured</CODE> function checks
to see if an exception has been raised in the current JNI session.

<A NAME="field"></A>
<H3>Accessing Fields</H3>

Accessing Java language fields from within native code is similar to
calling Java language methods. However, the set or field is retrieved
with a field ID, instead of a method ID.

<P>
The first thing you need to do is retrieve a field ID. You can
use the <CODE>GetFieldID</CODE> function, but specify the field name
and signature in place of the method name and signature.
Once you have the field ID, call a <CODE>Get&lt;type&gt;Field</CODE> function
to set the field value. The <CODE>&lt;type&gt;</CODE> is the
same as the native type being returned except the <CODE>j</CODE> is dropped
and the first letter is capitalized. For example, the
<CODE>&lt;type&gt;</CODE>
value
is <CODE>Int</CODE> for native type <CODE>jint</CODE>, and
<CODE>Byte</CODE>
for native type <CODE>jbyte</CODE>.

<P>
The <CODE>Get&lt;type&gt;Field</CODE> function result is returned as the
native type.  For example, to retrieve the <CODE>arraySize</CODE>
field in the <CODE>ArrayHandler</CODE>
class, call <CODE>GetIntField</CODE> as shown in the following
example.

<P>
The field can be set by calling the <CODE>env-&gt;SetIntField(jobj,
fid, arraysize)</CODE> functions. Static fields can be set by calling
<CODE>SetStaticIntField(jclass, fid, arraysize)</CODE> and retrieved
by calling <CODE>GetStaticIntField(jobj, fid)</CODE>.

<PRE>
&#35;include &lt;jni.h&gt;
&#35;include &lt;iostream.h&gt;
&#35;include "ArrayHandler.h"

JNIEXPORT void JNICALL Java_ArrayHandler_returnArray
(JNIEnv *env, jobject jobj){

    jobjectArray ret;
    int i;
    jint arraysize;
    jclass cls;
    jmethodID mid;
    jfieldID fid;

    char *message[5]= {"first",
                "second",
                "third",
                "fourth",
                "fifth"};

    ret=(jobjectArray)env-&gt;NewObjectArray(5,
        env-&gt;FindClass("java/lang/String"),
        env-&gt;NewStringUTF(""));

    for(i=0;i&lt;5;i++) {
      env-&gt;SetObjectArrayElement(
        ret,i,env-&gt;NewStringUTF(message[i]));
    }

    cls=env-&gt;GetObjectClass(jobj);
    mid=env-&gt;GetMethodID(cls,
        "sendArrayResults",
        "([Ljava/lang/String;)V");
    if (mid == 0) {
        cout &lt;&lt;Can't find method sendArrayResults";
        return;
    }

    env-&gt;ExceptionClear();
    env-&gt;CallVoidMethod(jobj, mid, ret);
    if(env-&gt;ExceptionOccurred()) {
       cout &lt;&lt; "error occured copying 
                        array back" &lt;&lt; endl;
       env-&gt;ExceptionDescribe();
       env-&gt;ExceptionClear();
    }
    fid=env-&gt;GetFieldID(cls, "arraySize",  "I");
    if (fid == 0) {
        cout &lt;&lt;Can't find field arraySize";
        return;
    }
    arraysize=env-&gt;GetIntField(jobj, fid);
    if(!env-&gt;ExceptionOccurred()) {
       cout&lt;&lt; "size=" &lt;&lt; arraysize &lt;&lt; endl;
    } else {
       env-&gt;ExceptionClear();
    }
    return;
}
</PRE>

<A NAME="thrd"></A>
<H3>Threads and Synchronization</H3> 

Although the native library is loaded once per class, individual threads
in an application written in the Java language use their own interface 
pointer when calling the native method. If you need to restrict access 
to a Java language object from within native code, you can either ensure 
that the Java language methods you call have explicit synchronization or 
you can use the JNI <CODE>MonitorEnter</CODE> and <CODE>MonitorExit</CODE> 
functions. 

<P>
In the Java langauge, code is protected by a monitor whenever 
you specify the <CODE>synchronized</CODE> keyword. In the Java programming 
language,  the monitor enter and exit routines
are normally hidden from the application developer.
In JNI, you need to explicitly delineate the entry and exit pointws
of thread safe code.

<P>
The following example uses a <CODE>Boolean</CODE> object to restrict 
access to the <CODE>CallVoidMethod</CODE> function.

<PRE>
  env-&gt;ExceptionClear();
  env-&gt;MonitorEnter(lock);
  env-&gt;CallVoidMethod(jobj, mid, ret);
  env-&gt;MonitorExit(lock);
  if(env-&gt;ExceptionOccurred()) {
    cout &lt;&lt; "error occured copying array back" &lt;&lt; endl;
    env-&gt;ExceptionDescribe();
    env-&gt;ExceptionClear();
  }
</PRE>

You may find that in cases where you want access to a local system resource
like a MFC window handle or message queue, it is better to use one
Java <CODE>Thread</CODE> and access the local threaded native event queue or 
messaging system from within the native code.

<A NAME="memory"></A>
<H3>Memory Issues</H3>

By default, JNI uses local references when creating objects inside
a native method. This means when the method returns, the references
are eligible to be garbage collected. If you want an object to persist 
across native method calls, use a global reference instead. A global 
reference is created from a local reference by calling 
<CODE>NewGlobalReference</CODE> on the the local reference. 

<P>
You can explicitly mark a reference for garbage collection by calling
<CODE>DeleteGlobalRef</CODE> on the reference. You can also create a weak 
style Global reference that is accessible outside the method, but can
be garbage collected. To create one of these references, call 
<CODE>NewWeakGlobalRef</CODE> and <CODE>DeleteWeakGlobalRef</CODE> 
to mark the reference for garbage collection.

<P>
You can even explicitly mark a local reference for garbage collection
by calling the <CODE>env-&gt;DeleteLocalRef(localobject)</CODE> method.
This is useful if you are using a large amount of temporary data.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -