你好,游客 登录 注册 搜索
背景:
阅读新闻

Android开发实践:JNI函数签名生成器

[日期:2014-12-16] 来源:Linux社区  作者:ticktick [字体: ]

“函数签名”在Android NDK开发中很常见,由于Java支持重载,仅靠函数名无法唯一确定一个方法。因此,JNI提供了一套签名规则,用一个字符串来唯一确定一个Java端定义的Native方法。

具体每一种Java数据类型对应的签名字符串如下所示(来自Oracle官网JNI的介绍):

Android开发实践:JNI函数签名生成器

原理其实并不复杂,每种基本类型对应一个单字符签名,而类则对应为"L"+类的全路径+";",数组类型则对应"["+元素类型的签名,函数的签名则是:(各参数类型签名)+ 返回类型的签名。

搞清楚了基本原理,我们就可以尝试自定义一个Java工具类,为Java的Native函数生成签名字符串了,具体代码如下:

/*
 *  COPYRIGHT NOTICE 
 *  Copyright (C) 2014, ticktick <lujun.hust@gmail.com>
 *  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));

输出结果截屏如下:

Android开发实践:JNI函数签名生成器

关于JNI函数签名生成器就介绍到这儿了,原理并不复杂所以我也没有进行过多的分析,希望这个工具类能够在大家今后的项目中派上用场,有任何疑问欢迎留言或者来信lujun.hust@gmail.com交流。

更多Android相关信息见Android 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=11

本文永久更新链接地址http://www.linuxidc.com/Linux/2014-12/110549.htm

linux
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数

       

评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款