Trong phần này chúng ta sẽ tìm hiểu cách gọi một phương thức Java từ C++.
Gọi một phương thức
Ví dụ chúng ta có lớp Java tên Methods
như sau:
class Methods { static { System.loadLibrary("Methods"); } private native void method(); private void hello() { System.out.println("Hello World"); } public static void main(String args[]) { new Methods().method(); } }
Phương thức native
tên là method(),
phương thức này sẽ được gọi qua C++, rồi từ C++ chúng ta gọi lại một phương thức của lớp Methods
này là hello()
.
Chúng ta làm điều đó như sau:
#include "Methods.h" JNIEXPORT void JNICALL Java_Methods_method (JNIEnv *e, jobject obj){ jclass cls = e->GetObjectClass(obj); jmethodID mid = e->GetMethodID(cls, "hello", "()V"); e->CallVoidMethod(obj, mid); }
Việc thực hiện cũng khá đơn giản.
Đầu tiên chúng ta lấy một đối tượng jclass
bằng phương thức GetObjectClass().
Sau đó lấy đối tượng jmethodID
bằng phương thức GetMethodID(),
phương thức này nhận vào đối tượng jclass,
tên lớp bằng chuỗi, rồi đến chuỗi mô tả tham số và kiểu trả về. Chuỗi mô tả này có dạng như sau:
"(kiểu_dữ_liệu_tham_số)kiểu_dữ_liệu_trả_về"
Các kiểu dữ liệu có tên như sau:
TÊN | KIỂU DỮ LIỆU |
Z | Boolean |
B | Byte |
C | Char |
S | Short |
I | Int |
J | Long |
F | Float |
D | Double |
L<tên_đẩy_đủ_của_lớp>; | Tên đầy đủ của lớp, có đường dẫn package |
[<một_trong_các_kiểu_trên> | Kiểu mảng |
Ví dụ "()V"
có nghĩa là phương thức đó không nhận vào tham số nào và có kiểu dữ liệu trả về là void
.
Giả sử trong Java có phương thức:
private String println(String);
Thì chúng ta điền là:
"(Ljava/lang/String;)Ljava/lang/String;"
Ví dụ về kiểu mảng:
Java:
public static void main(String[] args);
C++:
"([Ljava/lang/String;)V"
Lưu ý là nếu phương thức nhận vào kiểu void như f(void)
thì trong C++ chúng ta không ghi là "(V)I"
mà để trống, tức là "()I"
.
Hello World
Gọi phương thức static
Gọi một phương thức static cũng tương tự như gọi phương thức bình thường, chỉ khác tên hàm gọi.
Ví dụ chúng ta có code Java như sau:
class Methods { static { System.loadLibrary("Methods"); } private native void method(); private static void staticPrintFactorial(int n) { if(n >= 17 || n < 1) { System.out.println(n + " is too big or too small"); return; } int result = 1; for(int i = 2; i <= n ; i++) result *= i; System.out.println(result); } public static void main(String args[]) { new Methods().method(); } }
Chúng ta có một phương thức static
là staticPrintFactorial()
, phương thức này nhận vào một số nguyên và in ra giai thừa của số đó.
Chúng ta gọi phương thức này bên C++ như sau:
#include "Methods.h" JNIEXPORT void JNICALL Java_Methods_method (JNIEnv *e, jobject obj){ jclass cls = e->GetObjectClass(obj); jmethodID mid = e->GetStaticMethodID(cls, "staticPrintFactorial", "(I)V"); e->CallStaticVoidMethod(cls, mid, 10); e->CallStaticVoidMethod(cls, mid, 50); }
Chúng ta cũng lấy đối tượng jclass, jmethodID,
ở đây phương thức lấy là GetStaticMethodID(),
các tham số vẫn giống như phương thức GetMethod()
, để gọi phương thức static thì chúng ta dùng hàm CallStaticVoidMethod(),
phương thức này nhận vào đối tượng jclass,
đối tượng jmethodID
và các tham số.
3628800 50 is too big
Các phương thức tương tự khác có thể gọi là:
STATIC | NON STATIC | KIỂU DỮ LIỆU |
CallVoidMethod() |
CallStaticVoidMethod() |
void |
CallObjectMethod() |
CallStaticObjectMethod() |
jobject |
CallBooleanMethod() |
CallStaticBooleanMethod() |
jboolean |
CallByteMethod() |
CallStaticByteMethod() |
jbyte |
CallCharMethod() |
CallStaticCharMethod() |
jchar |
CallShortMethod() |
CallStaticShortMethod() |
jshort |
CallIntMethod() |
CallStaticIntMethod() |
jint |
CallLongMethod() |
CallStaticLongMethod() |
jlong |
CallFloatMethod() |
CallStaticFloatMethod() |
jfloat |
CallDoubleMethod() |
CallStaticDoubleMethod() |
jdouble |