Movatterモバイル変換


[0]ホーム

URL:


Jump to content
WikibooksThe Free Textbook Project
Search

Java Native Interface

100% developed
From Wikibooks, open books for an open world
<Java Programming
Thelatest reviewed version waschecked on16 April 2020. There aretemplate/file changes awaiting review.

3D ProgrammingJava Programming
Java Native Interface
Invoking C
NavigateAdvanced topic:()


The Java Native Interface (JNI) enables Java code running in a Java Virtual Machine (JVM) to call and to be called by native applications (programs specific to a hardware and operating system platform) and libraries written in other languages, such as C, C++ and assembly.

JNI can be used:

  • To implement or use features that are platform-specific.
  • To implement or use features that the standard Java class library does not support.
  • To enable an existing application—written in another programming language—to be accessible to Java applications.
  • To let a native method use Java objects in the same way that Java code uses these objects (a native method can create Java objects and then inspect and use these objects to perform its tasks).
  • To let a native method inspect and use objects created by Java application code.
  • For time-critical calculations or operations like solving complicated mathematical equations (native code may be faster than JVM code).

On the other hand, an application that relies on JNI loses the platform portability Java offers. So you will have to write a separate implementation of JNI code for each platform and have Java detect the operating system and load the correct one at runtime. Many of the standard library classes depend on JNI to provide functionality to the developer and the user (file I/O, sound capabilities...). Including performance- and platform-sensitive API implementations in the standard library allows all Java applications to access this functionality in a safe and platform-independent manner. Only applications and signed applets can invoke JNI. JNI should be used with caution. Subtle errors in the use of JNI can destabilize the entire JVM in ways that are very difficult to reproduce and debug. Error checking is a must or it has the potential to crash the JNI side and the JVM.

This page will only explain how to call native code from JVM, not how to call JVM from native code.

Calling native code from JVM

[edit |edit source]

In the JNI framework, native functions are implemented in separate .c or .cpp files. C++ provides a slightly simpler interface with JNI. When the JVM invokes the function, it passes aJNIEnv pointer, ajobject pointer, and any Java arguments declared by the Java method. A JNI function may look like this:

JNIEXPORTvoidJNICALLJava_ClassName_MethodName(JNIEnv*env,jobjectobj){/*Implement Native Method Here*/}

Theenv pointer is a structure that contains the interface to the JVM. It includes all of the functions necessary to interact with the JVM and to work with Java objects. Example JNI functions are converting native arrays to/from Java arrays, converting native strings to/from Java strings, instantiating objects, throwing exceptions, etc. Basically, anything that Java code can do can be done usingJNIEnv, albeit with considerably less ease.

On Linux and Solaris platforms, if the native code registers itself as a signal handler, it could intercept signals intended for the JVM. Signal chaining should be used to allow native code to better interoperate with JVM. On Windows platforms, Structured Exception Handling (SEH) may be employed to wrap native code in SEH try/catch blocks so as to capture machine (CPU/FPU) generated software interrupts (such as NULL pointer access violations and divide-by-zero operations), and to handle these situations before the interrupt is propagated back up into the JVM (i.e. Java side code), in all likelihood resulting in an unhandled exception.

C++ code

[edit |edit source]

For example, the following converts a Java string to a native string:

extern"C"JNIEXPORTvoidJNICALLJava_ClassName_MethodName(JNIEnv*env,jobjectobj,jstringjavaString){//Get the native string from javaStringconstchar*nativeString=env->GetStringUTFChars(javaString,0);//Do something with the nativeString//DON'T FORGET THIS LINE!!!env->ReleaseStringUTFChars(javaString,nativeString);}

The JNI framework does not provide any automatic garbage collection for non-JVM memory resources allocated by code executing on the native side. Consequently, native side code (such as C, C++, or assembly language) must assume the responsibility for explicitly releasing any such memory resources that it itself acquires.

C code

[edit |edit source]
JNIEXPORTvoidJNICALLJava_ClassName_MethodName(JNIEnv*env,jobjectobj,jstringjavaString){/*Get the native string from javaString*/constchar*nativeString=(*env)->GetStringUTFChars(env,javaString,0);/*Do something with the nativeString*//*DON'T FORGET THIS LINE!!!*/(*env)->ReleaseStringUTFChars(env,javaString,nativeString);}

Note that C++ JNI code is syntactically slightly cleaner than C JNI code because like Java, C++ uses object method invocation semantics. That means that in C, theenv parameter is dereferenced using(*env)-> andenv has to be explicitly passed toJNIEnv methods. In C++, theenv parameter is dereferenced usingenv-> and theenv parameter is implicitly passed as part of the object method invocation semantics.

Objective-C code

[edit |edit source]
JNIEXPORTvoidJNICALLJava_ClassName_MethodName(JNIEnv*env,jobjectobj,jstringjavaString){/*DON'T FORGET THIS LINE!!!*/JNF_COCOA_ENTER(env);/*Get the native string from javaString*/NSString*nativeString=JNFJavaToNSString(env,javaString);/*Do something with the nativeString*//*DON'T FORGET THIS LINE!!!*/JNF_COCOA_EXIT(env);}

JNI also allows direct access to assembly code, without even going through a C bridge.

Mapping types

[edit |edit source]

Native data types can be mapped to/from Java data types. For compound types such as objects, arrays and strings the native code must explicitly convert the data by calling methods in theJNIEnv. The following table shows the mapping of types between Java (JNI) and native code.

Native TypeJNI TypeDescriptionType signature
unsigned charjbooleanunsigned 8 bitsZ
signed charjbytesigned 8 bitsB
unsigned shortjcharunsigned 16 bitsC
shortjshortsigned 16 bitsS
longjintsigned 32 bitsI

long long
__int64

jlongsigned 64 bitsJ
floatjfloat32 bitsF
doublejdouble64 bitsD

In addition, the signature"L fully-qualified-class ;" would mean the class uniquely specified by that name; e.g., the signature"Ljava/lang/String;" refers to the classjava.lang.String. Also, prefixing[ to the signature makes the array of that type; for example,[I means the int array type. Finally, avoid signature uses theV code.Here, these types are interchangeable. You can usejint where you normally use anint, and vice-versa, without any typecasting required.

However, mapping between Java Strings and arrays to native strings and arrays is different. If you use ajstring in where achar * would be, your code could crash the JVM.

JNIEXPORTvoidJNICALLJava_ClassName_MethodName(JNIEnv*env,jobjectobj,jstringjavaString){// printf("%s", javaString);        // INCORRECT: Could crash VM!// Correct way: Create and release native string from Java stringconstchar*nativeString=(*env)->GetStringUTFChars(env,javaString,0);printf("%s",nativeString);(*env)->ReleaseStringUTFChars(env,javaString,nativeString);}

The encoding used for theNewStringUTF,GetStringUTFLength,GetStringUTFChars,ReleaseStringUTFChars,GetStringUTFRegion functions is not standard UTF-8, but modified UTF-8. The null character (U+0000) and codepoints greater than or equal to U+10000 are encoded differently in modified UTF-8. Many programs actually use these functions incorrectly and treat the UTF-8 strings returned or passed into the functions as standard UTF-8 strings instead of modified UTF-8 strings. Programs should use theNewString,GetStringLength,GetStringChars,ReleaseStringChars,GetStringRegion,GetStringCritical, andReleaseStringCritical functions, which use UTF-16LE encoding on little-endian architectures and UTF-16BE on big-endian architectures, and then use a UTF-16 to standard UTF-8 conversion routine.

The code is similar with Java arrays, as illustrated in the example below that takes the sum of all the elements in an array.

JNIEXPORTjintJNICALLJava_IntArray_sumArray(JNIEnv*env,jobjectobj,jintArrayarr){jintbuf[10];jinti,sum=0;// This line is necessary, since Java arrays are not guaranteed// to have a continuous memory layout like C arrays.env->GetIntArrayRegion(arr,0,10,buf);for(i=0;i<10;i++){sum+=buf[i];}returnsum;}

Of course, there is much more to it than this.

JNIEnv*

[edit |edit source]

A JNI environment pointer (JNIEnv*) is passed as an argument for each native function mapped to a Java method, allowing for interaction with the JNI environment within the native method. This JNI interface pointer can be stored, but remains valid only in the current thread. Other threads must first callAttachCurrentThread() to attach themselves to the VM and obtain a JNI interface pointer. Once attached, a native thread works like a regular Java thread running within a native method. The native thread remains attached to the VM until it callsDetachCurrentThread() to detach itself.

To attach to the current thread and get a JNI interface pointer:

JNIEnv *env;(*g_vm)->AttachCurrentThread (g_vm, (void **) &env, NULL);

To detach from the current thread:

(*g_vm)->DetachCurrentThread (g_vm);

HelloWorld

[edit |edit source]
Computer codeCode listing 10.1: HelloWorld.java
publicclassHelloWorld{privatenativevoidprint();publicstaticvoidmain(String[]args){newHelloWorld().print();}static{System.loadLibrary("HelloWorld");}}

HelloWorld.h

/* DO NOT EDIT THIS FILE - it is machine generated */#include<jni.h>/* Header for class HelloWorld */#ifndef _Included_HelloWorld#define _Included_HelloWorld#ifdef __cplusplusextern"C"{#endif/* * Class:     HelloWorld * Method:    print * Signature: ()V */JNIEXPORTvoidJNICALLJava_HelloWorld_print(JNIEnv*,jobject);#ifdef __cplusplus}#endif#endif

libHelloWorld.c

#include<stdio.h>#include"HelloWorld.h"JNIEXPORTvoidJNICALLJava_HelloWorld_print(JNIEnv*env,jobjectobj){printf("Hello World!\n");return;}

make.sh

#!/bin/sh# openbsd 4.9# gcc 4.2.1# openjdk 1.7.0JAVA_HOME=$(readlink-f/usr/bin/javac|sed"s:bin/javac::")exportLD_LIBRARY_PATH=$LD_LIBRARY_PATH:.javacHelloWorld.javajavahHelloWorldgcc-I${JAVA_HOME}/include-sharedlibHelloWorld.c-olibHelloWorld.sojavaHelloWorld
Computer codeCommands to execute on POSIX
chmod +x make.sh./make.sh

Advanced uses

[edit |edit source]

Not only can native code interface with Java, it can also draw on aJava API: java.awt.Canvas, which is possible with the Java AWT Native Interface. The process is almost the same, with just a few changes. The Java AWT Native Interface is only available since J2SE 1.3.


3D ProgrammingJava Programming
Java Native Interface
Invoking C
Retrieved from "https://en.wikibooks.org/w/index.php?title=Java_Programming/Java_Native_Interface&oldid=3675877"
Category:
Hidden category:

[8]ページ先頭

©2009-2025 Movatter.jp