nderstandable: The native interface the JDK defines has to be implementable on virtual machines (VMs) across all Java platforms.
On the Java side, to call a
native
method, you must first declare it
native
. Next, your program calls the
System.loadLibrary()
call to actually load the native-code library. (You will have compiled and created the library from your C/C++ compiler.)
That's the easy part. The tough part is on the C/C++ side. Given that a method of the same name cannot exist only across classes, but also
within
classes, Java requires a mechanism for uniquely identifying all methods. The C/C++-generated
native
-method name must satisfy that requirement. You do this through
mangling
, a way of encoding the prototype of the method in its name. For example, suppose you have a Java class that calls a
native
method as follows:
package apkg;
class acls {native int ameth(int i, double j);
{ ... }
However, the C/C++ definition of the above method is:
jint Java_apkg_acls_ameth__ID (JNIEnv *env, jobject jobj, jint i, jdouble j);
If you know the formula for mangling, you can peel the name apart to determine its
Java alias. The
jint
data type specifies this as a method returning a Java integer.
Java_apkg_acls_ameth
identifies this as a
native
Java method called
ameth
in package
apkg
, class
acls
. The double underscore precedes that part of the name that identifies the method's arguments. So, the
I
specifies the first argument as being a Java integer; the
D
specifies the second argument as being a Java double.
Notice that the C function's argument list includes two extra arguments:
*env
and
jobj
. The first argument is what the JNI refers to as the
interface pointer
. It's a pointer to a set of pointers to functions in the VM. It is through the interface pointer that the C/C++ code can call into the VM and access Java classes, objects, and data. The
jobj
argument is a reference to the current object (
this
).
By contrast, SuperCede's native interface is the quintessential no-brainer. On the Java
side, you merely have to declare the method as
native
. On the C/C++ side, you identify the method as you would were it a member of a C++ class. So, for the example above, the C++ code would be:
__java_int acls::ameth(__java_int i, __java_double j)
{ ... }
You fill the method's body with code, plop the file into the SuperCede integrated development environment (IDE), and compile. That's all there is to it. SuperCede takes care of the linking.