|
|
Start of Tutorial > Start of Trail > Start of Lesson |
Search
Feedback Form |
This section illustrates how to call Java methods from native language methods. Our example program,
Callbacks.java, invokes a native method. The native method then makes a call back to a Java method. To make things a little more interesting, the Java method again (recursively) calls the native method. This process continues until the recursion is five levels deep, at which time the Java method returns without making any more calls to the native method. To help you see this, the Java method and the native method print a sequence of tracing information.
Callbacks_nativeMethod, which is implemented in Callbacks.c. This native method contains a call back to the
Java method Callbacks.callback.
JNIEXPORT void JNICALL
Java_Callbacks_nativeMethod(JNIEnv *env, jobject obj, jint depth)
{
jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "(I)V");
if (mid == 0) {
return;
}
printf("In C, depth = %d, about to enter Java\n", depth);
(*env)->CallVoidMethod(env, obj, mid, depth);
printf("In C, depth = %d, back from Java\n", depth);
}
You can call an instance method by following these three steps:
GetObjectClass, which returns the Java class object that is the type of
the Java object.
GetMethodID, which performs a lookup for the Java method in
a given class. The lookup is based on the name of the method as well
as the method signature. If the method does not exist,
GetMethodID returns zero (0). An immediate return from the
native method at that point causes a
NoSuchMethodError to be thrown in the Java application code.
CallVoidMethod. The CallVoidMethod function invokes an instance method that has
void return type. You pass the object, method ID, and the actual
arguments to CallVoidMethod.
The JNI performs a symbolic lookup based on the method's name and type signature. This ensures that the same native method will work even after new methods have been added to the corresponding Java class.
The method name is the Java method name in UTF-8 form. Specify the
constructor of a class by enclosing the word
init within angle brackets (this appears as "<init>").
Note that the JNI uses the method signature to denote the return type of a Java
method. The signature (I)V, for example, denotes a Java
method that takes one argument of type int and has a return
type void. The general form of a method signature argument is:
"(argument-types)return-type"
The following table summarizes the encoding for the Java type signatures:
Java VM Type Signatures
Signature Java Programming Language Type ZbooleanBbyteCcharSshortIintJlongFfloatDdoubleLfully-qualified-class;fully-qualified-class [typetype [](arg-types)ret-typemethod type
For example, the Prompt.getLine method has the signature:
(Ljava/lang/String;)Ljava/lang/String;
Prompt.getLine takes one parameter, a Java String object, and the method type is also String.
The Callbacks.main method has the signature:
The signature indicates that the([Ljava/lang/String;)V
Callbacks.main method takes one parameter, a Java String object, and the method type is void.
Array types are indicated by a leading square bracket ([) followed by the type of the array elements.
javap to Generate Method Signatures
The Java class file disassembler tool, javap, helps you to eliminate the mistakes that can occur when deriving method signatures by hand. You can use the javap tool to print out member variables and method signatures for specified classes. Run the javap tool with the options -s and -p and give it the name of a Java class, as follows:
javap -s -p Prompt
This gives you the following output:
Compiled from Prompt.java
class Prompt extends java.lang.Object
/* ACC_SUPER bit set */
{
private native getLine (Ljava/lang/String;)Ljava/lang/String;
public static main ([Ljava/lang/String;)V
<init> ()V
static <clinit> ()V
}
The "-s" flag informs javap to output signatures rather than
normal Java types. The "-p" flag instructs javap to include private members.
When you invoke a method in the JNI, you pass the method ID to the actual method invocation function. Obtaining a method ID is a relatively expensive operation. Because you obtain the method ID separately from the method invocation, you need only perform this operation once. Thus, it is possible to first obtain the method ID one time and then use the method ID many times at later points to invoke the same method.
It is important to keep in mind that a method ID is valid only
for as long as the class from which it is derived is not unloaded. Once
the class is unloaded, the method ID becomes invalid. As a result, if you want
to cache the method ID, be sure to keep a live reference to the Java
class from which the method ID is derived. As long as the reference to
the Java class (the jclass value) exists, the native code keeps a live
reference to the class. The section Local and Global References explains how to keep a live reference even after
the native method returns and the jclass value goes out of
scope.
The JNI provides several ways to pass arguments to a Java method.
Most often, you pass the arguments following the method ID. There are
also two variations of method invocation functions that take arguments
in an alternative format. For example, the CallVoidMethodV function
receives all its arguments in one va_list type argument. A va_list type is a special C type that allows a C function to accept a variable number of arguments. The
CallVoidMethodA function expects the arguments in an array of
jvalue union types. The array of jvalue union types are as follows:
typedef union jvalue {
jboolean z;
jbyte b;
jchar c;
jshort s;
jint i;
jlong j;
jfloat f;
jdouble d;
jobject l;
} jvalue;
In addition to the CallVoidMethod function, the JNI also supports instance
method invocation functions with other return types, such as
CallBooleanMethod, CallIntMethod, and so on. The return type of the method
invocation function must match with the type of the Java method you wish to
invoke.
GetStaticMethodID rather than the function GetMethodID.
CallStaticVoidMethod,
CallStaticBooleanMethod, and so on.
JNIEnv argument. For example, suppose we add a incDepth class method into Callback.java.
static int incDepth(int depth) {return depth + 1};
We can call this class method incDepth from Java_Callback_nativeMethod
using the following JNI functions:
JNIEXPORT void JNICALL
Java_Callbacks_nativeMethod(JNIEnv *env, jobject obj, jint depth)
{
jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID mid = (*env)->GetStaticMethodID(env, cls, "incDepth", "(I)I");
if (mid == 0) {
return;
}
depth = (*env)->CallStaticIntMethod(env, cls, mid, depth);
...
CallNonvirtual<type>Method functions for this purpose. To call instance methods from the superclass that defined them, you do the following:
GetMethodID rather than
GetStaticMethodID.
CallNonvirtualVoidMethod,
CallNonvirtualBooleanMethod, and so on.
f, in Java using the following construct:
super.f();
|
|
Start of Tutorial > Start of Trail > Start of Lesson |
Search
Feedback Form |
Copyright 1995-2004 Sun Microsystems, Inc. All rights reserved.