歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Android開發實踐:JNI函數簽名生成器

“函數簽名”在Android NDK開發中很常見,由於Java支持重載,僅靠函數名無法唯一確定一個方法。因此,JNI提供了一套簽名規則,用一個字符串來唯一確定一個Java端定義的Native方法。

具體每一種Java數據類型對應的簽名字符串如下所示(來自Oracle官網JNI的介紹):

原理其實並不復雜,每種基本類型對應一個單字符簽名,而類則對應為"L"+類的全路徑+";",數組類型則對應"["+元素類型的簽名,函數的簽名則是:(各參數類型簽名)+ 返回類型的簽名。

搞清楚了基本原理,我們就可以嘗試自定義一個Java工具類,為Java的Native函數生成簽名字符串了,具體代碼如下:

/*
 *  COPYRIGHT NOTICE 
 *  Copyright (C) 2014, ticktick <[email protected]>
 *  http://www.linuxidc.com/
 * 
 *  @license under the Apache License, Version 2.0
 *
 *  @file    SignatureGen.java
 *  @brief  Implement a java class for jni signature generate
 * 
 *  @version 1.0   
 *  @author  ticktick
 *  @date    2014/12/15 
 *
 */
package com.ticktick.library;
 
import java.util.HashMap;
 
public class SignatureGen {
 
    public static final HashMap<String,String> Primitives = new HashMap<String, String>();
   
    static {
        Primitives.put(Void.class.getName(),"V");
        Primitives.put(Boolean.class.getName(),"Z");
        Primitives.put(Byte.class.getName(),"B");
        Primitives.put(Character.class.getName(),"C");
        Primitives.put(Short.class.getName(),"S");
        Primitives.put(Integer.class.getName(),"I");
        Primitives.put(Long.class.getName(),"J");
        Primitives.put(Float.class.getName(),"F");
        Primitives.put(Double.class.getName(),"D");           
    }
           
    public static String getSignature( Class ret, Class...params ) {
        StringBuilder builder = new StringBuilder();
        builder.append("(");
        for( Class param : params ) {
            builder.append(getSignature(param));   
        }     
        builder.append(")");
        builder.append(getSignature(ret));
        return builder.toString();
    }
       
    protected static String getSignature( Class param ) {
       
        StringBuilder builder = new StringBuilder();
        String name = "";
        if( param.isArray() ) {
            name = param.getComponentType().getName();
            builder.append("[");
        }
        else {
            name = param.getName();             
        } 
           
        if( Primitives.containsKey(name) ) {
        builder.append(Primitives.get(name));
        }
        else {       
            builder.append("L"+name.replace(".","/")+";");
        } 
     
        return builder.toString();
    }
}

該SignatureGen類提供一個支持變參的函數getSignature來獲取一個Java函數的簽名字符串,第一個參數為函數返回值類型的class對象,變參為每一個函數參數類型的class對象。

具體用法示例如下,打印出不同類型的函數的簽名字符串。

Log.d("Signature","void func() --> " + SignatureGen.getSignature(Void.class));
 
Log.d("Signature","boolean func() --> " + SignatureGen.getSignature(Boolean.class));
 
Log.d("Signature","int func(boolean a) --> " + SignatureGen.getSignature(Integer.class,Boolean.class));
 
Log.d("Signature","int func(boolean a,String b) --> " + SignatureGen.getSignature(Integer.class,Boolean.class,String.class));
 
Log.d("Signature","int func(byte[] c) --> " + SignatureGen.getSignature(Integer.class,Byte[].class));     
 
Log.d("Signature","long func(int n,String str,int arr) -->" + SignatureGen.getSignature(Long.class,Integer.class,String.class,Integer[].class));

輸出結果截屏如下:

關於JNI函數簽名生成器就介紹到這兒了,原理並不復雜所以我也沒有進行過多的分析,希望這個工具類能夠在大家今後的項目中派上用場,有任何疑問歡迎留言或者來信[email protected]交流。

更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11

Copyright © Linux教程網 All Rights Reserved