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
.
You can call an instance method by following these three steps: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); }
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 Z
boolean
B
byte
C
char
S
short
I
int
J
long
F
float
D
double
L
fully-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
.
We can call this class methodstatic int incDepth(int depth) {return depth + 1};
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 |