Java Language
जावा नेटिव इंटरफ़ेस
खोज…
पैरामीटर
पैरामीटर | विवरण |
---|---|
JNIEnv | जेएनआई पर्यावरण की ओर इशारा करता है |
jobject | वह वस्तु जिसने गैर- static native पद्धति को लागू किया |
jclass | वह वर्ग जिसने static native पद्धति को लागू किया |
टिप्पणियों
जेएनआई की स्थापना के लिए जावा और देशी कंपाइलर दोनों की आवश्यकता होती है। आईडीई और ओएस के आधार पर, कुछ सेटिंग की आवश्यकता होती है। ग्रहण के लिए एक गाइड यहाँ पाया जा सकता है । एक पूर्ण ट्यूटोरियल यहां पाया जा सकता है ।
ये विंडोज़ पर Java-C ++ लिंकेज स्थापित करने के लिए चरण हैं:
- जावा स्रोत फ़ाइलों (
.java
) कोjavac
का उपयोग करके कक्षाओं (.class
) में संकलित करें। - जावा का उपयोग करके
native
तरीकों से जावा वर्गों से हेडर (.h
) फाइलेंjavah
। ये फाइलें मूल कोड को "निर्देश" देती हैं जो इसे लागू करने के लिए जिम्मेदार हैं। -
native
तरीकों को लागू करने वाले C ++ स्रोत फ़ाइलों (.cpp
) में हेडर फाइलें (#include
) शामिल करें। - C ++ स्रोत फ़ाइलों को संकलित करें और एक लाइब्रेरी (
.dll
) बनाएं। इस लाइब्रेरी में देशी कोड कार्यान्वयन है। - लाइब्रेरी पथ (
-Djava.library.path
) निर्दिष्ट करें और इसे जावा स्रोत फ़ाइल (System.loadLibrary(...)
) में लोड करें।
कॉलबैक (देशी कोड से जावा विधियों को कॉल करना) के लिए एक विधि विवरणक निर्दिष्ट करना होगा। यदि वर्णनकर्ता गलत है, तो रनटाइम त्रुटि होती है। इस वजह से, यह हमारे लिए किए गए विवरणों के लिए सहायक है, यह javap -s
साथ किया जा सकता है।
जावा से C ++ विधियों को कॉल करना
जावा में स्थिर और सदस्य विधियों को मूल के रूप में चिह्नित किया जा सकता है ताकि यह इंगित किया जा सके कि उनका कार्यान्वयन एक साझा पुस्तकालय फ़ाइल में पाया जाना है। एक मूल विधि के निष्पादन पर, जेवीएम लोड किए गए पुस्तकालयों में एक समान कार्य की तलाश करता है (देखें देशी पुस्तकालयों को लोड करें ), एक साधारण नाम प्रबंधन योजना का उपयोग करते हुए, तर्क रूपांतरण और स्टैक सेटअप का प्रदर्शन करता है, फिर मूल कोड पर नियंत्रण सौंपता है।
जावा कोड
/*** com/example/jni/JNIJava.java **/
package com.example.jni;
public class JNIJava {
static {
System.loadLibrary("libJNI_CPP");
}
// Obviously, native methods may not have a body defined in Java
public native void printString(String name);
public static native double average(int[] nums);
public static void main(final String[] args) {
JNIJava jniJava = new JNIJava();
jniJava.printString("Invoked C++ 'printString' from Java");
double d = average(new int[]{1, 2, 3, 4, 7});
System.out.println("Got result from C++ 'average': " + d);
}
}
C ++ कोड
लक्ष्य वर्गों पर javah
टूल का उपयोग करके देशी फ़ंक्शन घोषणाओं वाली हैडर फाइलें उत्पन्न की जानी चाहिए। बिल्ड डायरेक्टरी में निम्न कमांड चला रहे हैं:
javah -o com_example_jni_JNIJava.hpp com.example.jni.JNIJava
... निम्नलिखित हेडर फ़ाइल का निर्माण करता है ( संक्षिप्तता के लिए छपी टिप्पणियाँ ):
// com_example_jni_JNIJava.hpp
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h> // The JNI API declarations
#ifndef _Included_com_example_jni_JNIJava
#define _Included_com_example_jni_JNIJava
#ifdef __cplusplus
extern "C" { // This is absolutely required if using a C++ compiler
#endif
JNIEXPORT void JNICALL Java_com_example_jni_JNIJava_printString
(JNIEnv *, jobject, jstring);
JNIEXPORT jdouble JNICALL Java_com_example_jni_JNIJava_average
(JNIEnv *, jclass, jintArray);
#ifdef __cplusplus
}
#endif
#endif
यहाँ एक उदाहरण कार्यान्वयन है:
// com_example_jni_JNIJava.cpp
#include <iostream>
#include "com_example_jni_JNIJava.hpp"
using namespace std;
JNIEXPORT void JNICALL Java_com_example_jni_JNIJava_printString(JNIEnv *env, jobject jthis, jstring string) {
const char *stringInC = env->GetStringUTFChars(string, NULL);
if (NULL == stringInC)
return;
cout << stringInC << endl;
env->ReleaseStringUTFChars(string, stringInC);
}
JNIEXPORT jdouble JNICALL Java_com_example_jni_JNIJava_average(JNIEnv *env, jclass jthis, jintArray intArray) {
jint *intArrayInC = env->GetIntArrayElements(intArray, NULL);
if (NULL == intArrayInC)
return -1;
jsize length = env->GetArrayLength(intArray);
int sum = 0;
for (int i = 0; i < length; i++) {
sum += intArrayInC[i];
}
env->ReleaseIntArrayElements(intArray, intArrayInC, 0);
return (double) sum / length;
}
उत्पादन
ऊपर दिए गए उदाहरण वर्ग को चलाने से निम्नलिखित आउटपुट मिलते हैं:
जावा से C ++ 'PrintString' का आह्वान किया
सी ++ 'औसत' से परिणाम मिला: 3.4
C ++ (कॉलबैक) से जावा विधियों को कॉल करना
मूल विधि से जावा विधि को कॉल करना दो चरणों वाली प्रक्रिया है:
-
GetMethodID
JNI फ़ंक्शन के साथ एक विधि सूचक प्राप्त करें, विधि नाम और विवरणक का उपयोग करके; - कॉल की एक
Call*Method
यहाँ सूचीबद्ध कार्य करता है ।
जावा कोड
/*** com.example.jni.JNIJavaCallback.java ***/
package com.example.jni;
public class JNIJavaCallback {
static {
System.loadLibrary("libJNI_CPP");
}
public static void main(String[] args) {
new JNIJavaCallback().callback();
}
public native void callback();
public static void printNum(int i) {
System.out.println("Got int from C++: " + i);
}
public void printFloat(float i) {
System.out.println("Got float from C++: " + i);
}
}
C ++ कोड
// com_example_jni_JNICppCallback.cpp
#include <iostream>
#include "com_example_jni_JNIJavaCallback.h"
using namespace std;
JNIEXPORT void JNICALL Java_com_example_jni_JNIJavaCallback_callback(JNIEnv *env, jobject jthis) {
jclass thisClass = env->GetObjectClass(jthis);
jmethodID printFloat = env->GetMethodID(thisClass, "printFloat", "(F)V");
if (NULL == printFloat)
return;
env->CallVoidMethod(jthis, printFloat, 5.221);
jmethodID staticPrintInt = env->GetStaticMethodID(thisClass, "printNum", "(I)V");
if (NULL == staticPrintInt)
return;
env->CallVoidMethod(jthis, staticPrintInt, 17);
}
उत्पादन
C ++: 5.221 से फ्लोट हुआ
C ++: 17 से int प्राप्त किया
वर्णन करने वाला
संकलित .class
फ़ाइल पर javap प्रोग्राम का उपयोग करके डिस्क्रिप्टर्स (या आंतरिक प्रकार के हस्ताक्षर ) प्राप्त किए जाते हैं। यहाँ javap -p -s com.example.jni.JNIJavaCallback
का आउटपुट है:
Compiled from "JNIJavaCallback.java"
public class com.example.jni.JNIJavaCallback {
static {};
descriptor: ()V
public com.example.jni.JNIJavaCallback();
descriptor: ()V
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
public native void callback();
descriptor: ()V
public static void printNum(int);
descriptor: (I)V // <---- Needed
public void printFloat(float);
descriptor: (F)V // <---- Needed
}
देशी पुस्तकालय लोड हो रहे हैं
जावा में साझा लाइब्रेरी फ़ाइलों को लोड करने के लिए सामान्य मुहावरे निम्नलिखित हैं:
public class ClassWithNativeMethods {
static {
System.loadLibrary("Example");
}
public native void someNativeMethod(String arg);
...
System.loadLibrary
को कॉल लगभग हमेशा स्थिर होती है ताकि क्लास लोडिंग के दौरान हो सके, यह सुनिश्चित करें कि साझा लाइब्रेरी लोड होने से पहले कोई भी देशी विधि निष्पादित नहीं हो सके। हालांकि निम्नलिखित संभव है:
public class ClassWithNativeMethods {
// Call this before using any native method
public static void prepareNativeMethods() {
System.loadLibrary("Example");
}
...
यह आवश्यक होने तक साझा लाइब्रेरी लोडिंग को स्थगित करने की अनुमति देता है, लेकिन java.lang.UnsatisfiedLinkError
s से बचने के लिए अतिरिक्त देखभाल की आवश्यकता होती है।
लक्ष्य फ़ाइल लुकअप
साझा लाइब्रेरी फ़ाइलों पथ द्वारा परिभाषित में खोज की जाती है java.library.path
प्रणाली संपत्ति है, जो का उपयोग कर ओवरराइड किया जा सकता -Djava.library.path=
रनटाइम पर JVM तर्क:
java -Djava.library.path=path/to/lib/:path/to/other/lib MainClassWithNativeMethods
सिस्टम पथ विभाजकों के लिए देखें: उदाहरण के लिए, विंडोज उपयोग करता है ;
के बजाय :
ध्यान दें कि System.loadLibrary
एक प्लेटफ़ॉर्म-आश्रित तरीके से लाइब्रेरी फ़ाइलनाम को हल करता है: ऊपर दिया गया कोड स्निपेट, Linux पर libExample.so
नामक फ़ाइल और Windows पर Example.dll
अपेक्षा करता है।
के लिए एक वैकल्पिक System.loadLibrary
है System.load(String)
है, जो एक साझा लाइब्रेरी फ़ाइल का पूर्ण पथ लेता है, circumventing java.library.path
देखने:
public class ClassWithNativeMethods {
static {
System.load("/path/to/lib/libExample.so");
}
...