“函数签名”在Android NDK开发中很常见,由于Java支持重载,仅靠函数名无法唯一确定一个方法。因此,JNI提供了一套签名规则,用一个字符串来唯一确定一个Java端定义的Native方法。
天镇网站制作公司哪家好,找创新互联建站!从网页设计、网站建设、微信开发、APP开发、成都响应式网站建设公司等网站项目制作,到程序开发,运营维护。创新互联建站从2013年开始到现在10年的时间,我们拥有了丰富的建站经验和运维经验,来保证我们的工作的顺利进行。专注于网站建设就选创新互联建站。
具体每一种Java数据类型对应的签名字符串如下所示(来自Oracle官网JNI的介绍):
原理其实并不复杂,每种基本类型对应一个单字符签名,而类则对应为"L"+类的全路径+";",数组类型则对应"["+元素类型的签名,函数的签名则是:(各参数类型签名)+ 返回类型的签名。
搞清楚了基本原理,我们就可以尝试自定义一个Java工具类,为Java的Native函数生成签名字符串了,具体代码如下:
/* * COPYRIGHT NOTICE * Copyright (C) 2014, ticktick* http://ticktick.blog.51cto.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 Primitives = new HashMap (); 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函数签名生成器就介绍到这儿了,原理并不复杂所以我也没有进行过多的分析,希望这个工具类能够在大家今后的项目中派上用场,有任何疑问欢迎留言或者来信lujun.hust@gmail.com交流,或者关注我的新浪微博 @卢_俊 获取最新的文章和资讯。