Jni C/C++开发基础之基础聚集(Android、Java范畴)

1,在jni C/C++中调用java代码的流程:
1)获取类
2)调用静态方法时,先获取methodID(使用GetStaticMethodID),然后使用类似java invoke的形式将类和methodID作为参数调用CallStaticMethod方法,即实现对java方法的调用。
3)调用非静态方法时,还需要类的实例object,相关的方法有GetMethodID、Call***Method


2,JNIEnv类中有如下几个简单的函数可以取得类(jclass)
1)jclass FindClass(const char* clsName)  根据类名来查找一个类,完整类名。
2)jclass GetObjectClass(jobject obj)   根据一个对象,获取该对象的类
3)jclass GetSuperClass(jclass obj)     获取一个类的父类


FindClass 会在classpath系统环境变量下寻找类,需要传入完整的类名,并注意包与包之间是用"/"而不是"."来分割
如:jclass cls_string= env->FindClass("java/lang/String");
 

以上相关函数都在jni.h定义。

 

3,使用GetMethodID获取methodID前需要知道什么?
1)方法签名
使用javap命令来产生签名:
javap -s -p [full class Name]
-s 表示输出签名信息
-p 同-private,输出包括private访问权限的成员信息


比如类TestNative的源码:

 

package video1;    
import java.util.Date;    
public class TestNative {    
    public String name="Test";    
    public int number =100;    
    public int signTest(int i,Date date,int[] arr){    
        System.out.println("Sign Test");    
        return 0;    
    }    
    //native关键字修饰的方法,其内容是C/C++编写的,java中不必为它编写具体的实现    
    public native void sayHello();    
    public static void main(String[] args) {    
        System.loadLibrary("NativeCode");    
        TestNative tn = new TestNative();    
        tn.sayHello();    
    }    
}

 


使用javap命令获取编辑后类的方法签名

 

 

javap -s -private video1.TestNative


输出:

 

 

Compiled from "TestNative.java"    
public class video1.TestNative extends java.lang.Object{    
public java.lang.String name;    
  Signature: Ljava/lang/String;    
public video1.TestNative();    
  Signature: ()V    
public int signTest(int, java.util.Date, int[]);    
  Signature: (ILjava/util/Date;[I)I    
public native void sayHello();    
  Signature: ()V    
public static void main(java.lang.String[]);    
  Signature: ([Ljava/lang/String;)V    
}

 


2)java数据类型对应的签名定义

 

 

类型           相应的签名  
boolean        Z  
byte           B  
char           C  
short          S  
int            I  
long           J  
float          F  
double         D  
void           V  
object         L用/分隔包的完整类名:   Ljava/lang/String; 
Array          [签名          [I      [Ljava/lang/Object;  
Method         (参数1类型签名 参数2类型签名···)返回值类型签名 



3)方法签名举例:

 

void f1()                         ()V
int f2(int, long)                 (IJ)I
boolean f3(int[])                 ([I)Z
double f4(String, int)            (Ljava/lang/String;I)D
void f5(int, String [], char)     (I[Ljava/lang/String;C)V
特别注意:Object后面一定有分号(;)结束的,多个对象参数中间也用分号(;)来分隔



4)对于jmethodID GetMethodID(jclass clazz, const char *name, const char *sign)
clazz代表该属性所在的类,name表示方法名称,sign是签名
(什么是签名,签名是对函数参数和返回值的描述。对同一个函数,在java中允许重载,这个时候就需要这个sign来进行区分了)

举例:

 

 

char *getAlgorithm(JNIEnv *env, jbyteArray jbyteArrays) {
    //获取类java.security.MessageDigest
    jclass digest_clazz = (env)->FindClass("java/security/MessageDigest");
    if (digest_clazz == NULL) {
        return NULL;
    }


    //获取方法 MessageDigest.getInstance(String algorithm)的ID,这个方法的返回值类型是MessageDigest
    //如果类中没有此方法,会返回NULL。但不报异常
    jmethodID methodID_getInstance = (env)->GetStaticMethodID(digest_clazz, "getInstance", ""
            "(Ljava/lang/String;)Ljava/security/MessageDigest;");


    //调用方法 MessageDigest.getInstance(String algorithm),将字符串 "MD5" 作为参数
    jobject digest_object = (env)->CallStaticObjectMethod(digest_clazz, methodID_getInstance,
                                                          env->NewStringUTF("MD5"));


    //获取方法 void update(byte[] bytes)的ID
    jmethodID methodID_update = (env)->GetMethodID(digest_clazz, "update", "([B)V");
    //调用上述方法,jbyteArrays作为字节数组类型的参数
    (env)->CallVoidMethod(digest_object, methodID_update, jbyteArrays);


    //获取方法 byte[] digest()的ID
    jmethodID methodID_digest = (env)->GetMethodID(digest_clazz, "digest", "()[B");
    //调用上述方法
    jbyteArray digestArray = (jbyteArray) (env)->CallObjectMethod(digest_object, methodID_digest);


    jbyte *array = (env)->GetByteArrayElements(digestArray, NULL);
    jsize len = (env)->GetArrayLength(digestArray);


    unsigned char *encrypt = (unsigned char *) calloc((size_t) len + 1, sizeof(unsigned char));
    for (int j = 0; j < len; ++j) {
        encrypt[j] = (unsigned char) array[j];
    }
    encrypt[len] = '\0';
    (env)->ReleaseByteArrayElements(digestArray, array, 0);
    return getHexChar(encrypt, len);
}

 


参考:

http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/jniTOC.html

https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html
https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值