2015-04-23 14 views
7

Bắt đầu sử dụng JNI để gọi các phương thức java tĩnh từ C++. Cụ thể, sau khi nhận được một lớp jclass (sử dụng FindClass) và một jmethodID (bằng cách sử dụng GetStaticMethodID), tôi đã tiếp tục gọi cho chuỗi CallStatic * MethodA routine. Hóa ra rằng tất cả các thường trình này lấy một lớp jclass làm tham số đầu tiên. Tôi bắt đầu tự hỏi tại sao đối tượng lớp là cần thiết: vì tất cả các thông tin được cung cấp trong GetStaticMethodID, đối tượng lớp có vẻ không cần thiết cho JVM để hoàn thành công việc. Sau đó tôi đã thử gọi những thói quen này trong khi truyền NULL cho tham số đầu tiên và lời gọi đã thành công.JNI Gọi các phương thức tĩnh. Đối tượng lớp có cần thiết không?

Câu hỏi của tôi: Có an toàn khi gọi các phương thức này với đối tượng lớp NULL không?

Ưu đãi là: Nếu nó thực sự là hợp pháp, tôi sẽ không phải cache đối tượng lớp cho các cuộc gọi tiếp theo đến các phương thức tĩnh (trong khi nhớ gọi NewGlobalRef ....). Caching jmethodID sẽ là đủ.

+1

Dalvik [không sử dụng tham số jclass] (https://android.googlesource.com/platform/dalvik.git/+/android-4.2.2_r1/vm/Jni.cpp) trong 'CallStatiC## _ jname ## Method', do đó, nó thực sự xuất hiện như thể đi qua 'NULL' sẽ là ok. Tôi không thể nói bất cứ điều gì về các JVM khác mặc dù. – Michael

+1

Đặc điểm kỹ thuật của JNI nói cần thiết, vì vậy cần thiết. Tôi sẽ không viết mã phụ thuộc vào một quirk của một JVM cụ thể. – EJP

+0

Nó chỉ hoạt động vì phương thức tĩnh của bạn không gọi các phương thức tĩnh khác từ cùng một lớp, cũng không sử dụng các biến lớp tĩnh! – Christophe

Trả lời

2

Không, nó là tuyệt đối KHÔNG an toàn để gọi hàm tĩnh như vậy với con trỏ lớp rỗng (hoặc không hợp lệ).

Thực hành của bạn có thể rất thành công, ví dụ: nếu phương pháp tĩnh của bạn không đề cập đến bất kỳ thành viên lớp tĩnh nào khác. Tuy nhiên, nếu phương thức java tĩnh của bạn đề cập đến bất kỳ thành viên tĩnh nào khác, JVM của bạn sẽ cần đến con trỏ lớp hợp lệ.

Ví dụ:

Hãy demo này đơn giản Java MyTest.java:

public class MyTest { 
    public static void mymain() { 
     System.out.println("Hello, World in java from mymain"); 
     System.out.println(magic_counter); // this will cause a segfault if 
    }          // class pointer is null 
    private static int magic_counter=777; 
} 

Và gọi nó với những điều sau JNI C++ đoạn mã

... // JVM already loaded and initialised 

jclass cls2 = env->FindClass("MyTest"); 
if(cls2 == nullptr) { 
    cerr << "ERROR: class not found !"; 
} 
else { 
    cout << "Class MyTest found" << endl; 
    jmethodID mid = env->GetStaticMethodID(cls2, "mymain", "()V"); 
    if(mid == nullptr) 
     cerr << "ERROR: method void mymain() not found !" << endl; 
    else { 
     env->CallStaticVoidMethod(cls2, mid); 
     cout << endl; 
    } 
} 

Calling GetStaticMethodID(nullptr, "mymain", "()V"); sẽ thất bại. Bởi vì khi mymain() thực hiện, nó sẽ cố gắng truy cập vào biến tĩnh magic_number. JVM sau đó sẽ sử dụng con trỏ lớp mà bạn đã cung cấp và giả sử đó là một con trỏ vaild được trả về bởi một lớp được nạp. Nhưng vì nó là null, hệ thống sẽ phân đoạn.

+0

Tôi đã thử ví dụ của bạn và không có segfault. Tôi đang sử dụng Oracle jdk/jre 1.8.0.45 trên Linux cho java và g ++ để biên dịch C++. Bạn đang sử dụng JVM nào và trên hệ điều hành nào? BTW, tôi phải thiếu một cái gì đó ... Tôi thấy khó hiểu, rằng một khi ranh giới bản địa/JAVA đã được vượt qua và mã JAVA đang được thực hiện, JVM - trong thời gian chạy - vẫn cần phải đến lớp đối tượng được truyền vào bên C++ của đường biên để giải quyết các thành viên/phương thức tĩnh lồng nhau ... – user4212919

+0

chỉ để đảm bảo .... Tôi đang chuyển NULL tới CallStaticVoidMethod (NULL, giữa), không cho GetStaticMethodID (cls2, "mymain", "() V") ... – user4212919

+0

@ user4212919 tốt, tôi đã cùng một phiên bản java, chạy ở chế độ 64 bit, nhưng trên windows 8.1 với MSVC2013. Tôi có thể chạy ví dụ này với NULL thay vì cls2 nếu và chỉ khi tôi nhận xét ra việc in ấn của magic_number. – Christophe

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