Java native static methods

Java native static methods

This section illustrates how you can call Java methods from native 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.

Calling a Java Method from Native Code

Let us focus on the implementation of Callbacks_nativeMethod , 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); >
  • Your native method calls GetObjectClass . This returns the Java class object to which the Java object belongs.
  • Your native method then calls GetMethodID . This 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 0. An immediate return from the native method at that point causes a NoSuchMethodError to be thrown in Java code.
  • Lastly, your native method calls CallVoidMethod . This invokes an instance method that has void return type. You pass the object, method ID, and the actual arguments to CallVoidMethod .

Forming the Method Name and Method Signature

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 method name for a constructor of a class by enclosing the word init within angle brackets (this appears as «»).

Note that the JNI uses method signatures to denote the type of Java methods. The signature (I)V , for example, denotes a Java method that takes one argument of type int and has return type void . The general form of a method signature argument is:

Читайте также:  Интерполяционный кубический сплайн python

The following table summarizes the encoding for the Java type signatures:

Java VM Type Signatures
(Ljava/lang/String;)Ljava/lang/String;

Array types are indicated by a leading square bracket ([) followed by the type of the array elements.

Using javap to Generate Method Signatures

To eliminate the mistakes in deriving method signatures by hand, you can use the javap tool to print out method signatures. For example, by running:

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 ()V static ()V >

The «-s» flag informs javap to output signatures rather than normal Java types. The «-p» flag causes private members to be included.

Calling Java Methods Using Method IDs

In JNI, you pass the method ID to the actual method invocation function. This makes it possible to first obtain the method ID, which is a relatively expensive operation, 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 as long as the class from which it is derived is not unloaded. Once the class is unloaded, the method ID becomes invalid. So if you want to cache the method ID, make 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.

Passing Arguments to Java Methods

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 the arguments in a va_list , and the CallVoidMethodA function expects the arguments in an array of jvalue union types:

typedef union jvalue < jboolean z; jbyte b; jchar c; jshort s; jint i; jlong j; jfloat f; jdouble d; jobject l; >jvalue;

Besides 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 Java method you wish to invoke.

Calling Static Methods

  • Obtain the method ID using GetStaticMethodID , as opposed to GetMethodID .
  • Pass the class, method ID, and arguments to the family of static method invocation functions: CallStaticVoidMethod , CallStaticBooleanMethod , and so on.
static int incDepth(int depth) ;
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);

Calling Instance Methods of a Superclass

  • Obtain the method ID from the superclass using GetMethodID , as opposed to GetStaticMethodID) .
  • Pass the object, superclass, method Id, and arguments to the family of nonvirtual invocation functions: CallNonvirtualVoidMethod , CallNonvirtualBooleanMethod , and so on.
Читайте также:  Java timeout for method

Источник

Write Native Methods in Java

Write Native Methods in Java

  1. What Are Native Methods in Java
  2. Write Native Methods in Java Programs

This article takes you through various steps necessary to learn how to write native methods in Java programs.

What Are Native Methods in Java

The native keyword is a modifier in Java programming, used with methods only. It represents that this particular method is written in the native code via Java Native Interface (JNI).

The native (or foreign) methods are implemented in C, C++, or any other platform-dependent code.

[public/protected/private] native [returnType] youMethodName(); 

Write Native Methods in Java Programs

Listed below is the multi-step process to write native methods in Java programs:

Write the Java program containing the native method’s declaration and the main method to call the native method.
Compile the Java program with the main method and declare the specified native method.
Use javah with -jni flag to create the header file for the native method.
Write the code for the native method in the programming language you like, for instance, C/C++.
Create the shared library to compile the implementation and header files.
Finally, execute/run the Java Program.

Let’s follow all of these steps to call native methods in the Java program.

Write a Java Program

class nativeDemoClass  //declaration of the native method  public native void showMessage();   //load native C library  static  System.loadLibrary("nativedemoclass"); //lowercase of classname  >   //java main method  public static void main (String[] args)  nativeDemoClass demo = new nativeDemoClass();  demo.showMessage();  > > 

We must include the native keyword as a method’s declaration part in the Java program if we implement the method in a programming language other than Java.

This native keyword tells the Java compiler that this specific method is a native programming language method. Remember, the declaration of a native method in the Java program provides the method signature only.

We have a static block that loads the native C library in which we have written the implementation of the showMessage() method. Have you noticed that we are passing a string to the System.loadLibrary() method?

Why is it so? It is because this static block from the nativeDemoClass class will load the appropriate library, named nativedemoclass .

Let’s move to the second step and compile the Java program.

Compile the Java Program

Use the command given below to compile the Java program.

javac nativeDemoClass.java 

After successfully compiling the Java program, we get the nativeDemoClass.class file.

Create a Header File

Use the following command to create a header file.

Here, -h produces the C/C++ header files and places the generated file into the specified directory. We use dot ( . ) to keep the generated header file in the current directory.

javac -h . nativeDemoClass.java 

You may find on the Internet that javah creates C/C++ header files, which was correct until JDK 8. According to the oracle, javah is deprecated now, but we have an alternative solution given above.

The nativeDemoClass.h file looks as follows. We do not edit this because it is a machine-generated file.

/* DO NOT EDIT THIS FILE - it is machine generated */ #include  /* Header for class nativeDemoClass */  #ifndef _Included_nativeDemoClass #define _Included_nativeDemoClass #ifdef __cplusplus  extern "C"  #endif  /* * Class: nativeDemoClass * Method: showMessage * Signature: ()V */ JNIEXPORT void JNICALL Java_nativeDemoClass_showMessage  (JNIEnv *, jobject);  #ifdef __cplusplus  > #endif #endif 

The JNIEXPORT void JNICALL Java_nativeDemoClass_showMessage declares the C function in this header file. We can have multiple function signatures if the nativeDemoClass has more native methods.

  • Prefix as Java_
  • The package name
  • The class name
  • native method’s name

Each section is separated by an underscore ( _ ), as shown graphically below:

Write Native Methods in Java - Naming Convention

Further, the JNIEnv* refers to the Java Native Interface environment that allows us to access the Java Native Interface (JNI) methods. The jobject references this object of Java programming.

Write the Native Code

#include #include "nativeDemoClass.h" #include  JNIEXPORT void JNICALL Java_nativeDemoClass_showMessage(JNIEnv *env, jobject obj)   printf("Hello world!\n");  return; > 

The implementation of Java_nativeDemoClass_showMessage is pretty straightforward because we are only using a printf() statement to print Hello world . Remember, this .c file has three headers, jni.h , stdio.h , and nativeDemoClass.h created in the previous step.

Create the Shared Library

Use the following command to create the shared library. We must have build tools for visual studio to use the CL command.

cl -Ic:\java\jdk-17.0.2\include -Ic:\java\jdk-17.0.2\include\win32 -LD nativeDemoClassImp.c -Fenativedemoclass.dll 

Remember, the Java program uses the following method to load the shared library, named nativedemoclass at run time.

System.loadLibrary("nativedemoclass"); 

Run the Java Program

Finally, use the command given below to run the Java program.

You will see Hello world! on the command line if you have done everything correctly.

Write Native Methods in Java - Output

Mehvish Ashiq is a former Java Programmer and a Data Science enthusiast who leverages her expertise to help others to learn and grow by creating interesting, useful, and reader-friendly content in Computer Programming, Data Science, and Technology.

Related Article — Java Method

Источник

Оцените статью