2010-02-09 46 views
5

Có thể gọi một hàm CPP gốc bằng JNI có các đối số chung không? Giống như sau:Generics Java và JNI

public static native <T, U, V> T foo(U u, V v); 

và sau đó gọi nó thích:

//class Foo, class Bar, class Baz are already defined; 
Foo f = foo(new Bar(), new Baz()); 

bất cứ ai có thể vui lòng cung cấp cho tôi với một mẫu được thực sự làm điều này hoặc một số hướng dẫn trên mạng mà thực hiện điều này? Tôi hỏi vì trong chức năng CPN JNI của tôi (gọi là JVM), tôi nhận được lỗi liên kết không hài lòng.

CPP Mã sau:

JNIEXPORT jobject JNICALL Java_Processor_process (JNIEnv *env, jclass processor_class, jobject obj1, jobject obj2) 
{ 
    jclass bar_class = env->FindClass("Bar"); 
    jmethodID getFooMethod = env->GetMethodID(bar_class, "getFoo", "()Ljava/lang/Object;"); 
//getFoo() is defined as `public Foo getFoo();` in Bar.java 
    return env->CallObjectMethod(obj1, getFooMethod); 
} 

EDIT:

Tôi đã thử bằng cách sửa đổi mã nhưng bây giờ tôi nhận được NoSuchMethodError:

đang

Java:

public static native <U, V> String foo(U u, V v); 
//... 
String str = foo(new Bar(), new Baz()); 

Mã CPP:

JNIEXPORT jstring JNICALL Java_Processor_process (JNIEnv *env, jclass processor_class, jobject obj1, jobject obj2) 
{ 
    jclass bar_class = env->FindClass("Bar"); 
    jmethodID getFooMethod = env->GetMethodID(bar_class, "getFoo", "()Ljava/lang/String;"); 
    //getFoo() is now defined as `public String getFoo();` in Bar.java 
    return env->CallObjectMethod(obj1, getFooMethod); 
} 

Điều này có nghĩa là JNI không hỗ trợ cho generics hoặc tôi thiếu gì đó?

+1

JNI không làm bất kỳ điều gì kỳ diệu. Như với mã Java chuẩn bog, bạn sẽ tạo 'T' từ đâu? –

Trả lời

7

Có nhiều câu hỏi liên quan đến xóa lớp trên ngăn xếp ngăn xếp (ví dụ: Get generic type of java.util.List), những gì bạn đang tìm cách làm là không thể với chính JNI cũng như Java. Chữ ký kiểu thời gian chạy của foo là (trong cả hai thế giới, hoặc trên thực tế, chỉ có một thế giới) Object foo(Object u, Object v), sẽ làm một lớp ngầm ẩn trên giá trị trả về cho bất kỳ kiểu nào bạn gọi nó.

Như bạn có thể nhận thấy (và như đã đề cập trong nhận xét cho câu hỏi của bạn), không có cách nào để bạn biết loại T là gì.

EDIT:
Bằng cách này, phương pháp getFoo là nghĩa vụ để trở về 'Foo', vì vậy không nên bạn được làm

jmethodID getFooMethod = env->GetMethodID(bar_class, "getFoo", "()LFoo;"); 

Hãy đến với suy nghĩ của nó, toàn bộ chuỗi cuộc gọi của bạn có vẻ ra khỏi vị trí ... bạn đã có một số foo là chuỗi trả về tự nhiên. Bây giờ foo tìm kiếm getFoo trong Bar, trả về 'Foo' và trả về kết quả của cuộc gọi đó trực tiếp, có hiệu quả cố gắng trả lại Foo (Foo getFoo() theo nhận xét), nơi chuỗi được mong đợi.

8

Nói chung, bạn nên luôn sử dụng javap -s để nhận được chữ ký của các phương thức bạn sẽ tìm kiếm trong JNI. Đừng đoán.

+2

Tôi không đồng ý. Thư viện bản địa của tôi có 51 chức năng và tôi đã mã hóa tất cả chúng không có vấn đề gì. Nó thực sự không phải ở tất cả các khó khăn để có được chúng ngay nếu bạn chỉ dừng lại và suy nghĩ cho một phút về những gì bạn đang làm. –

+3

Nhưng tại sao chạy * bất kỳ * rủi ro nào, khi bạn có một công cụ đã chính xác 100%? – EJP

+2

'javah' sẽ lấy một tệp lớp và xuất tệp tiêu đề C chứa các hàm chính xác mà bạn cần thực hiện –