JNI – Tham số JNI


Được đăng vào ngày 20/12/2016 | 0 bình luận
Đánh giá bài viết

Chúng ta sẽ tìm hiểu về các tham số trong các phương thức native.

Để làm việc này thì chúng ta sẽ viết hàm native trong Java, hàm này sẽ nhận vào một chuỗi kí tự, bên C++ sẽ nhận chuỗi kí tự này và in ra màn hình.

Đầu tiên chúng ta tạo file .java như sau:

public class Arg {
    static {
        System.loadLibrary("Arg");
    }
 
    private native void sendName(String name);
 
    public static void main(String args[]){
        String name = "Pho Code";
        Arg arg = new Arg();
        arg.sendName(name);
    }
}

Phương thức nativesendName(), chúng ta truyền vào với chuỗi là "Pho Code".

Sau đó dịch và tạo file header C++:

javac Arg.java
...
javah -classpath . -jni Arg
...

File Arg.h với phương thức native được chuyển sang C++ sẽ được sinh ra như thế này:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Arg */

#ifndef _Included_Arg
#define _Included_Arg
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class: Arg
 * Method: sendName
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_Arg_sendName
 (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

Trong đó JNIEXPORTJNICALL là các macro được định nghĩa trong file jni.h, các macro này cho biết là hàm đó có thể được gọi từ nơi khác (giống như từ khóa extern trong C). Bạn cũng có thể để ý tên phương thức được tạo nên từ Java_<tên_lớp>_<tên_phương_thức>.

Và trong phương thức native này bao giờ cũng sẽ có ít nhất là 2 tham số JNIEnv*jobject. Về cơ bản thì đối tượng JNIEnv* là một con trỏ trỏ tới một con trỏ, con trỏ này trỏ tới một mảng, mảng này lại chứa các con trỏ trỏ tới các phương thức của JNI để chúng ta có thể sử dụng.

Tham số jobject sẽ khác nhau tùy thuộc vào phương thức native ở bên phía Java như thế nào. Nếu phương thức native là phương thức static thì jobject sẽ đại diện cho lớp chứa phương thức đó, còn nếu không thì jobject sẽ là đối tượng được tạo ra từ lớp đó.

Ngoài 2 tham số bắt buộc phải có kia thì chúng ta có thể truyền thêm các tham số khác như bình thường.

Bây giờ chúng ta viết code cho phương thức native C++ như sau:

#include <iostream>
#include "Arg.h"

JNIEXPORT void JNICALL Java_Arg_sendName (JNIEnv *e, jobject obj, jstring name){
    const char *str;
    str = e->GetStringUTFChars(name, JNI_FALSE);
    if(str == NULL)
        return;
    std::cout << "Hello " << str;
    e->ReleaseStringUTFChars(name, str);
}

Tham số jstring ở bên Java là biến là một đối tượng java.lang.String, nhưng C++ thì lại không có kiểu dữ liệu nào như thế này. Do đó chúng ta phải chuyển kiểu dữ liệu, may mắn là trong số các phương thức JNI có phương thức để chuyển, ở đây chúng ta dùng phương thức GetStringUTFChars(), phương thức này sẽ chuyển jstring sang một mảng char, tham số đầu tiên là biến jstring, tham số thứ 2 là một giá trị bool, chúng ta có thể dùng JNI_FALSE hoặc JNI_TRUE, ý nghĩa của tham số thứ 2 là có muốn thực hiện copy hay không.

Sau khi chuyển xong chúng ta có thể in ra như thường, ngoài ra chúng ta cũng có thể kiểm tra xem việc chuyển đổi có thành công hay không bằng cách kiểm tra xem strNULL hay không.

Cuối cùng chúng ta gọi phương hức ReleaseStringUTFChars() để xóa biến này khỏi bộ nhớ.

Bây giờ chúng ta có thể dịch và build file thư viện và chạy:

g++ -I"C:\Program Files\Java\jdk1.8.0_65\include" 
-I"C:\Program Files\Java\jdk1.8.0_65\include\win32 -o Arg.o -c Arg.cpp
...
g++ -Wl,--add-stdcall-alias -shared -o Arg.dll Arg.o
...
java -classpath . -Djava.library.path=. Arg
Hello Pho Code

Ngoài 2 phương thức GetStringUTFChars()ReleaseStringUTFChars() ở trên thì còn rất nhiều phương thức khác như:

  • jstring NewString(JNIEnv *, const jchar *, jsize): tạo chuỗi java.lang.String
  • jsize GetStringLength(JNIEnv *, jstring): lấy độ dài của chuỗi jstring
  • const jchar * GetStringChars(JNIEnv *, jstring, jboolean *)tương tự GetStringUTFChars()
  • void ReleaseStringChars(JNIEnv *, jstring, const jchar *): tương tự ReleaseStringUTFChars()

Bạn có thể xem danh sách tại đây.







Trả lời


Lưu ý: bọc code trong cặp thẻ [code language="x"][/code] để highlight code.


Ví dụ:


[code language="cpp"]


    std::cout << "Hello world";


[/code]



Các ngôn ngữ được hỗ trợ gồm: actionscript3, bash, clojure, coldfusion, cpp, csharp, css, delphi, diff, erlang, fsharp, go, groovy, html, java, javafx, javascript, latex, matlab, objc, perl, php, powershell, python, r, ruby, scala, sql, text, vb, xml.

Thư điện tử của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *