Вы находитесь на странице: 1из 6

Native Methods from the Java Side

Native methods within a Java class are very simple. Any Java method can be transformed into a
native method-simply delete the method body, add a semicolon at the end, and prefix the native
keyword. The following Java method

public int myMethod(byte[] data)


{
...
}
becomes

public native int myMethod(byte[] data);


Where does the method body get implemented? In a Java-called native library that gets loaded
into Java at runtime. The class of the above method would have to cause the library to be loaded.
The best way to accomplish the load is to add a static initializer to the class:

static
{
System.loadLibrary("myMethodLibrary");
}
Static code blocks are executed once by the system when the class is first introduced. Any
operations may be specified, but library loading is the most common use. If the static block fails,
the class will not be loaded. This ensures that no native methods are executed without the
underlying libraries.

That's all there is to Java-side native methods. All the complexity is hidden within the native
library. A native method appears to Java like all other real Java methods. In fact, all the Java
modifiers (public, private, and so forth) apply to native methods as well.

Writing Native Methods

The Java runtime was implemented in the C programming language, so currently the only native
language supported is C. The entry points into a C library that can be called from Java are called
stubs. When you execute a native method call, a stub is entered. Java tries to ease the transition
into native code by supplying a tool to generate a C header file and stub module.

Note
Any language that can link with and be called by C can be used to implement a
native method. The C language is needed only to provide the actual interface with
Java. Any additional, non-Java processing could be done in another language, such
as Pascal.

Using Javah

Javah is the tool used to generate C files for Java classes; here's how you use it:
javah [options] class
The following table briefly lists the options available. By default, javah will create a C header (.h)
file in the current directory for each class listed on the command line. Class names are specified
without the trailing .class. Therefore, to generate the header for SomeName.class, use the
following command:

javah SomeName

Javah options

Option Description
-verbose Causes progress strings to be sent to stdout
-version Prints the version of javah
-o outputfile Overrides default file creation;uses only this file
-d directory Overrides placement of output in current directory
-td tempdirectory Overrides default temp directory use
-stubs Creates C code module instead of header module
-classpath path Overrides default classpath

Note
If the class you want is within a package, then the package name must be specified
along with the class name: javah java.net.Socket. In addition, javah will prefix the
package name to the output filename: java_net_Socket.h.

The following code is a simple class with native methods. The class was chosen because it uses
most of the Java types. Compile this class and pass it to javah.

A simple class using native methods

public class Demonstration


{
public String publicName;
private String privateName;
public static String publicStaticName;
private static String privateStatucName;

public native void method1();


public native int method2(boolean b, byte by, char c, short s);
public native byte[] method3(byte data[], boolean b[]);
public native String[] method4(int num, long l, float f, double d);

static
{
System.loadLibrary("Demonstration");
}
}

The javah output of the above class is below.


Javah output header of Demonstration class

/* DO NOT EDIT THIS FILE - it is machine generated */


#include <native.h>
/* Header for class Demonstration */

#ifndef _Included_Demonstration
#define _Included_Demonstration
struct Hjava_lang_String;

typedef struct ClassDemonstration {


struct Hjava_lang_String *publicName;
struct Hjava_lang_String *privateName;
/* Inaccessible static: publicStaticName */
/* Inaccessible static: privateStatucName */
} ClassDemonstration;
HandleTo(Demonstration);

#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) void Demonstration_method1(struct HDemonstration *);
__declspec(dllexport) long Demonstration_method2(struct HDemonstration
*,/*boolean*/ long,
char,unicode,short);
__declspec(dllexport) HArrayOfByte *Demonstration_method3(struct HDemonstration
*,
HArrayOfByte *,HArrayOfInt *);
__declspec(dllexport) HArrayOfString *Demonstration_method4(struct HDemonstration
*,long,
int64_t,float,double);
#ifdef __cplusplus
}
#endif
#endif
The class has been transformed into a C structure. Each class member is represented, except for
static fields. Representation in a structure has an interesting side effect. Native methods have
access to all non-static fields, including private class members. You are free to read and alter any
member of the class.

Now focus your attention on the four native method prototypes. Each method has been renamed
by prefixing the class name to the method name. Had this class been contained in a package, the
package name also would have been added. Each method has an additional argument. All native
methods have a this pointer that allows the function to access the variables of its associated
class. This argument is often referred to as an "automatic" parameter. Java will add this
parameter to your methods automatically.
The final piece to the puzzle is the HandleTo() macro. Every object in Java is represented in a
structure called a JHandle. The format of this structure for the Demonstration class is as follows:

struct HDemonstration
{
ClassDemonstration *obj;
methodtable *methods;
}

The HandleTo() macro names the JHandle by adding an H to the passed name. To access any
member of a JHandle class, you must dereference it with the unhand() macro. This macro has
the opposite effect of HandleTo(). The following line retrieves a string member from the
Demonstration class:

Hjava_lang_String str = unhand(demoPtr)->publicName;

The code for the unhand() macro shows the conversion:

#define unhand(o) ((o)->obj)

Structure member obj is obviously the class structure, but what of the other structure member?
Typically, structure member methods will contain a pointer to an internal Java runtime structure
that represents all the information on a class. This includes the Java byte codes, the exception
table, any defined constants, and the parent class. There are times, however, when the variable
is not a pointer at all. Java has reserved the lower 5 bits of the pointer for flags. If all 5 bits are
zero, then the value is a pointer. If the lower 5 bits are non-zero, then the methods field becomes
a typecode. You will encounter typecodes whenever you handle arrays.

The Stubs Code

Run the following command on the Demonstration class:

javah -stubs Demonstration


The output will be a C file in the current directory. The following shows the result.

The output of javah -stubs Demonstration

/* DO NOT EDIT THIS FILE - it is machine generated */


#include <StubPreamble.h>

/* Stubs for class Demonstration */


/* SYMBOL: "Demonstration/method1()V", Java_Demonstration_method1_stub */
declspec(dllexport) stack_item *
Java_Demonstration_method1_stub(stack_item *_P_,struct execenv *_EE_) {
extern void Demonstration_method1(void *);
(void) Demonstration_method1(_P_[0].p);
return _P_;
}
/* SYMBOL: "Demonstration/method2(ZBCS)I", Java_Demonstration_method2_stub */
declspec(dllexport) stack_item *
Java_Demonstration_method2_stub(stack_item *_P_,struct execenv *_EE_) {
extern long Demonstration_method2(void *,long,long,long,long);
_P_[0].i = Demonstration_method2(_P_[0].p,((_P_[1].i)),
&nbs p; ((_P_[2].i)),((_P_[3].i)),
&nbs p; ((_P_[4].i)));
return _P_ + 1;
}
/* SYMBOL: "Demonstration/method3([B[Z)[B", Java_Demonstration_method3_stub */
declspec(dllexport) stack_item *
Java_Demonstration_method3_stub(stack_item *_P_,struct execenv *_EE_) {
extern long Demonstration_method3(void *,void *,void *);
_P_[0].i = Demonstration_method3(_P_[0].p,((_P_[1].p)),((_P_[2].p)));
return _P_ + 1;
}
/* SYMBOL: "Demonstration/method4(IJFD)[Ljava/lang/String;",
Java_Demonstration_method4_stub */
declspec(dllexport) stack_item *
Java_Demonstration_method4_stub(stack_item *_P_,struct execenv *_EE_) {
Java8 _t2;
Java8 _t4;
extern long Demonstration_method4(void *,long,int64_t,float,double);
_P_[0].i = Demonstration_method4(_P_[0].p,
&nbs p; ((_P_[1].i)),
&nbs p; GET_INT64(_t2, _P_+2),
&nbs p; ((_P_[4].f)),
&nbs p; GET_DOUBLE(_t5, _P_+5));
return _P_ + 1;
}
This file contains the stub functions for each of the four native methods. It is the stub's job to
translate Java data structures into a C format. Once this is done, the stub will then enter your C
function. Sometimes the stub will have to do a little extra work to make the transition. For
example, take a look at method4's stub. The Java stack is made up of 32-bit words. Java data
types long and double each command 64 bits of storage. The stub code calls "helper" functions
to extract the data from the Java stack. The stubs will perform all the work necessary, no matter
how complex, to interface the Java stack to C.

The other interesting feature of the stub module is the SYMBOL comment at the top of each
method. Java uses a system of method "signatures" to identify functions. The signature contains
the method arguments and the return type; the symbols are explained below.

Method signature symbols

Type Signature Character


byte B
char C
class L
end of class ;
float F
double D
function (
end of function )
int I
long J
short S
void V
boolean Z

Signatures are important because they enable you to make calls back into the Java system. If
you know the class, name, and signature of a method, then these elements can be used to
invoke the Java method from within a C library. The format of a signature is as follows
:
"package_name/class_name/method_name(args*)return_type"
Arguments can be any combination of the characters shown above. Class name arguments are
written like this:

Lclass_name;
The semicolon signals the end of the class name, just as the right (closing) parenthesis signals
the end of an argument list. Arrays are followed by the array type:

[B for an array of bytes


[Ljava/langString; for an array of objects (in this case, Strings)
The Demonstration class is not actually going to be used; it's merely a convenient tool to
demonstrate the C features of Java's runtime environment.

Вам также может понравиться