2009-06-18 35 views

Trả lời

90

Các câu trả lời khác là chính xác về mặt kỹ thuật, nhưng không hữu ích cho người không có kinh nghiệm JNI. :-)

Thông thường, để JVM tìm thấy các hàm gốc của bạn, chúng phải được đặt tên theo một cách nhất định. ví dụ: đối với java.lang.Object.registerNatives, hàm C tương ứng có tên là Java_java_lang_Object_registerNatives. Bằng cách sử dụng registerNatives (hoặc đúng hơn, chức năng JNI RegisterNatives), bạn có thể đặt tên cho hàm C của mình bất cứ điều gì bạn muốn.

Dưới đây là đoạn code liên quan đến C (từ OpenJDK 6):

static JNINativeMethod methods[] = { 
    {"hashCode", "()I",     (void *)&JVM_IHashCode}, 
    {"wait",  "(J)V",     (void *)&JVM_MonitorWait}, 
    {"notify",  "()V",     (void *)&JVM_MonitorNotify}, 
    {"notifyAll", "()V",     (void *)&JVM_MonitorNotifyAll}, 
    {"clone",  "()Ljava/lang/Object;", (void *)&JVM_Clone}, 
}; 

JNIEXPORT void JNICALL 
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls) 
{ 
    (*env)->RegisterNatives(env, cls, 
          methods, sizeof(methods)/sizeof(methods[0])); 
} 

(Chú ý rằng Object.getClass không có trong danh sách, nó vẫn sẽ được gọi bằng cái tên "tiêu chuẩn" của Java_java_lang_Object_getClass.) Đối với các chức năng được liệt kê, các hàm C được liên kết như được liệt kê trong bảng đó, đó là thủ công hơn là viết một loạt các chức năng chuyển tiếp.

Đăng ký chức năng gốc cũng hữu ích nếu bạn đang nhúng Java vào chương trình C và muốn liên kết đến các hàm trong chính ứng dụng (trái ngược với thư viện dùng chung) hoặc các chức năng đang được sử dụng không được xuất ", vì chúng thường không được tìm thấy bởi cơ chế tra cứu phương pháp chuẩn. Việc đăng ký các hàm gốc cũng có thể được sử dụng để "rebind" một phương thức gốc sang một hàm C khác (hữu ích nếu chương trình của bạn hỗ trợ các mô-đun tải và nạp tự động, chẳng hạn).

Tôi khuyến khích mọi người đọc JNI book, nói về điều này và hơn thế nữa. :-)

+1

Bạn đã viết tên chức năng JNI được trang trí đầy đủ, điều này làm cho nó khó hiểu: là 'Java_java_lang_Object_registerNatives' được VM tự động gọi, hoặc mã c/C++ phải gọi hàm đó và không cần tất cả java gobblygook – Pavel

+0

@Pavel Theo mặc định, phương thức native 'methodName' trong lớp' fully.qualified.ClassName' được tìm kiếm dưới tên C 'Java_fully_qualified_ClassName_methodName' (mà mã C-side của bạn phải xuất). Bạn có thể gọi phương thức 'RegisterNatives' của' JNIEnv' để ghi đè liên kết này. Nói cách khác, nếu bạn không sử dụng 'RegisterNatives' trước," tất cả java gobblygook "[sic] là bắt buộc. –

+0

Ah, ok, do đó, bằng cách xuất chỉ có 1 hàm 'Java_java_lang_Object_registerNatives' tôi thực sự có thể liên kết tất cả các công cụ JNI của tôi bằng cách kiểm tra giá trị của' cls'. Tôi đã bỏ lỡ phần registerNatives thực sự là một phần của java. Vì vậy, ... khi một số lớp sắp được sử dụng, thứ tự các hành động mà JVM sử dụng để liên kết người bản địa là gì? Dường như nếu người bản địa chưa đăng ký (từ c/C++), thì JVM sẽ kiểm tra tất cả các tên đã xuất này, nếu chúng không có mặt thì nó sẽ cố gắng sử dụng Object.registerNatives (hoặc cách khác xung quanh?). Nhân tiện, liên kết sách jni đã chết. – Pavel

-9

Vì bạn đã xem mã nguồn để tìm nó, nó khá dễ đoán?

Đó là một phương pháp gốc và được gọi là registerNatives, vì vậy tôi đoán nó đăng ký các đối tượng với nền tảng cơ bản.

Nó cũng là riêng tư, vì vậy có thể không có gì phải lo lắng.

+20

Bạn phải là một lập trình viên nguồn đóng ("di chuyển theo, không có gì để xem xét"), không được sử dụng cho ý tưởng của những người thực sự muốn biết những gì diễn ra "dưới sự che phủ". Đủ rồi. :-P –

+2

Darn, rõ ràng phải không? – aberrant80

8

Điều gì có thể hơi khó hiểu là mã được hiển thị cho java.lang.Object.registerNatives trong câu trả lời trước chỉ là một ví dụ về cách đăng ký chức năng gốc. Đây là mã mà (trong việc thực hiện OpenJDK) đăng ký các hàm gốc cho đối tượng lớp. Để đăng ký các hàm gốc cho lớp của riêng bạn, bạn phải gọi hàm JNI RegisterNatives từ mã gốc trong thư viện của riêng bạn. Điều này nghe có vẻ hơi tròn, nhưng có một vài cách để phá vỡ vòng lặp.

  1. Thực hiện theo các ví dụ về thực hiện này của lớp Object:

    a. Trong lớp Java của bạn, khai báo một phương thức nguyên gốc (tốt nhất là static) có tên là registerNatives (hoặc bất kỳ tên nào khác. Nó không quan trọng).

    b. Trong mã gốc của bạn, hãy xác định hàm có tên Java_<your fully qualified class name>_registerNatives, trong đó có cuộc gọi đến hàm JNI RegisterNatives.

    c. Đảm bảo rằng trong mã Java của bạn, phương thức Java registerNatives của bạn được gọi trước khi có bất kỳ cuộc gọi nào đến các phương thức gốc khác.

HOẶC

  1. Sử dụng JNI_OnLoad

    a. Trong thư viện gốc của bạn, hãy xác định hàm jint JNI_OnLoad(JavaVM *vm, void *reserved). Trong phần thân của hàm này, hãy gọi hàm JNI RegisterNatives.

    b. Máy ảo Java sẽ tự động tìm kiếm và gọi JNI_OnLoad khi thư viện gốc của bạn được tải bởi System.loadLibrary, mà bạn nên đã gọi, có thể trong trình khởi tạo tĩnh cho lớp của bạn. (Bạn nhận được các yêu cầu env con trỏ bằng cách gọi GetEnv chức năng trong bảng rằng vm điểm con trỏ đến.)

Các vấn đề liên quan