“函数签名”在Android NDK开发中很常见,由于Java支持重载,仅靠函数名无法唯一确定一个方法。因此,JNI提供了一套签名规则,用一个字符串来唯一确定一个Java端定义的Native方法。
具体每一种Java数据类型对应的签名字符串如下所示(来自Oracle官网JNI的介绍):
原理其实并不复杂,每种基本类型对应一个单字符签名,而类则对应为"L"+类的全路径+";",数组类型则对应"["+元素类型的签名,函数的签名则是:(各参数类型签名)+ 返回类型的签名。
搞清楚了基本原理,我们就可以尝试自定义一个Java工具类,为Java的Native函数生成签名字符串了,具体代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
/*
* COPYRIGHT NOTICE
* Copyright (C) 2014, ticktick <lujun.hust@gmail.com>
* 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<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对象。
具体用法示例如下,打印出不同类型的函数的签名字符串。
1
2
3
4
5
6
7
8
9
10
11
|
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函数签名生成器就介绍到这儿了,原理并不复杂所以我也没有进行过多的分析,希望这个工具类能够在大家今后的项目中派上用场。
本文转自 Jhuster 51CTO博客,原文链接:http://blog.51cto.com/ticktick/1590209,如需转载请自行联系原作者