[Ljava/lang/String(String类型的JNI字段描述符)

本文详细介绍了JNI中的描述符系统,包括字段描述符和方法描述符的格式与含义,解释了如何通过这些描述符来表示Java的基本类型、数组类型以及类类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


转载 2016年03月21日 10:15:46

 “([Ljava/lang/String;)V” 它是一种对函数返回值和参数的编码。这种编码叫做JNI字段描述符(JavaNative Interface FieldDescriptors)。一个数组int[],就需要表示为这样"[I"。如果多个数组double[][][]就需要表示为这样 "[[[D"。也就是说每一个方括号开始,就表示一个数组维数。多个方框后面,就是数组 的类型。

 

     如果以一个L开头的描述符,就是类描述符,它后紧跟着类的字符串,然后分号“;”结束。

 

     比如"Ljava/lang/String;"就是表示类型String;

 

     "[I"就是表示int[];

 

     "[Ljava/lang/Object;"就是表示Object[]。

 

     JNI方法描述符,主要就是在括号里放置参数,在括号后面放置返回类型,如下:

 

   (参数描述符)返回类型

 

    当一个函数不需要返回参数类型时,就使用”V”来表示。

 

    比如"()Ljava/lang/String;"就是表示String f();

 

    "(ILjava/lang/Class;)J"就是表示long f(int i, Class c);

 

    "([B)V"就是表示void String(byte[] bytes);

 

Java 类型

符号

Boolean

Z

Byte

B

Char

C

Short

S

Int

I

Long

J

Float

F

Double

D

Void

V

objects对象

以"L"开头,以";"结尾,中间是用"/" 隔开的包及类名。比如:Ljava/lang/String;如果是嵌套类,则用$来表示嵌套。例如 "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"

 

     另外数组类型的简写,则用"["加上如表A所示的对应类型的简写形式进行表示就可以了,比如:[I 表示 int [];[L/java/lang/objects;表示Objects[],另外。引用类型(除基本类型的数组外)的标示最后都有个";"

 

     例如:

 

             "()V" 就表示void Func();

 

             "(II)V" 表示 void Func(int, int);

 

             "(Ljava/lang/String;Ljava/lang/String;)I".表示 int Func(String,String)

<think>我们正在分析Smali代码中字符串拼接的逻辑,特别是使用StringBuilder的append方法的情况。 在Java中,字符串拼接通常会被编译器优化为使用StringBuilder,以避免创建多个临时字符串对象。在Smali代码中,我们可以看到对应的StringBuilder操作。 步骤: 1. 创建StringBuilder对象:通常使用new-instance指令创建StringBuilder实例,然后调用其构造方法。 2. 调用append方法:多次调用append方法将各个部分添加到StringBuilder中。 3. 最后调用toString方法:将StringBuilder对象转换为字符串。 在Smali中,这些操作会表现为一系列的invoke指令(如invoke-direct, invoke-virtual)和对象操作指令(new-instance, const-string等)。 示例分析: 假设我们有如下Java代码: String str = "a" + "b" + "c"; 在编译后,它会被转换为类似以下代码: StringBuilder sb = new StringBuilder(); sb.append("a"); sb.append("b"); sb.append("c"); String str = sb.toString(); 在Smali中,这段代码可能如下所示: 注意:Smali代码中寄存器使用(如v0, v1等)和指令的详细步骤。 代码示例: 我们逐条分析Smali指令: 1. 创建StringBuilder实例: new-instance v0, Ljava/lang/StringBuilder; # 创建StringBuilder对象,引用存储在v0 invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V # 调用构造方法 2. 拼接字符串"a": const-string v1, "a" # 将字符串常量"a"加载到寄存器v1 invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; # 调用append方法,注意返回值是StringBuilder本身,但通常我们忽略返回值(因为不需要链式调用时,可以丢弃) 注意:append方法返回StringBuilder对象本身(用于链式调用),但在Smali中,如果我们不需要这个返回值(即不继续使用它),可以忽略。所以这里通常没有move-result-object,因为我们继续使用v0(即原来的StringBuilder对象)。 3. 拼接字符串"b": const-string v1, "b" # 加载字符串"b"到v1(注意:可以复用v1,因为之前的值已经使用过了) invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; 4. 拼接字符串"c": const-string v1, "c" invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; 5. 调用toString方法: invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; # 调用toString move-result-object v1 # 将结果字符串移动到v1 最后,v1中存储了最终拼接的字符串。 但是,在实际情况中,编译器可能会进行优化,比如将多个字符串常量直接拼接成一个,但如果是变量拼接,则通常会使用上述模式。 另外,注意在循环中拼接字符串的情况,这时会看到循环体内重复调用append方法。 重要:在Smali中,我们可能会看到多个append方法调用,每个调用都针对一个部分(可能是字符串常量、变量、或其他类型)。对于不同类型,有对应的append方法重载(如append(int), append(Object)等)。 示例2:拼接字符串和整数 Java代码: String s = "Value: " + 123; Smali代码: new-instance v0, Ljava/lang/StringBuilder; invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V const-string v1, "Value: " invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; const/16 v1, 0x7b # 123的十六进制 invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder; # 注意这里是append(I) invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; move-result-object v1 注意:整数123被编译为const/16 v1, 0x7b,然后调用append(I)方法。 总结:在Smali中分析字符串拼接,关键是识别StringBuilder对象的创建、一系列的append调用(注意参数类型)以及最后的toString调用。 相关问题: 1. 在Smali中,如何识别字符串拼接被优化为StringBuilder模式? 2. 除了StringBuilder,Smali中还有哪些字符串拼接方式? 3. 在循环中进行字符串拼接时,Smali代码有何特点?</think>### Smali代码中字符串拼接的StringBuilder.append分析 在Smali语言中,字符串拼接通常通过`StringBuilder`的`append`方法实现,这是Java编译器优化字符串操作的常见方式(如`"a" + "b"`会被编译为`StringBuilder`操作)。以下是逐步分析: --- #### 步骤1:创建StringBuilder对象 字符串拼接前会先创建`StringBuilder`实例: ```smali new-instance v0, Ljava/lang/StringBuilder; # 创建StringBuilder对象 invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V # 调用构造方法 ``` - **`new-instance`**:在寄存器`v0`中创建新对象 - **`invoke-direct`**:调用构造方法初始化对象[^1] --- #### 步骤2:使用append方法拼接字符串 通过多次调用`append`方法逐步构建字符串: ```smali const-string v1, "Hello, " # 加载字符串常量到v1 invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; # 第一次append const-string v1, "World!" # 加载新字符串 invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; # 第二次append ``` - **关键点**: - `append`方法返回`StringBuilder`对象本身(支持链式调用),但Smali中通常忽略返回值 - 寄存器`v1`被复用存放不同字符串常量 - 非字符串类型(如int)会调用重载方法,例如: ```smali const/16 v1, 0x64 # 加载整数100 (0x64) invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder; # append(int) ``` --- #### 步骤3:转换为最终字符串 拼接完成后调用`toString`获取结果: ```smali invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; move-result-object v2 # 获取最终字符串 ``` - **`move-result-object`**:必须紧跟`invoke-virtual`捕获返回值[^2] - 最终结果存储在`v2`寄存器中 --- #### 完整示例分析 Java代码:`String result = "A" + 1 + "B";` 对应的Smali实现: ```smali new-instance v0, Ljava/lang/StringBuilder; # 步骤1: 创建StringBuilder invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V const-string v1, "A" # 步骤2: 拼接"A" invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; const/4 v1, 0x1 # 加载整数1 invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder; # 拼接int const-string v1, "B" # 拼接"B" invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; # 步骤3: 转换 move-result-object v2 # v2 = "A1B" ``` --- #### 性能优化建议 1. **复用StringBuilder**:在循环中避免重复创建`StringBuilder` ```smali # 错误:每次循环创建新实例 :loop_start new-instance v0, Ljava/lang/StringBuilder; # 低效 ... # 正确:循环外创建,循环内reset new-instance v0, Ljava/lang/StringBuilder; :loop_start invoke-virtual {v0}, Ljava/lang/StringBuilder;->setLength(I)V # 清空内容 ``` 2. **预估容量**:减少扩容开销(Smali中需手动设置) ```smali const/16 v1, 100 invoke-direct {v0, v1}, Ljava/lang/StringBuilder;-><init>(I)V # 初始化容量 ``` --- #### 常见问题排查 - **类型不匹配**:`append`参数类型需与方法签名一致,如`append(I)`对应`int`,`append(Ljava/lang/String;)`对应字符串[^3] - **结果丢失**:忘记`move-result-object`会导致返回值丢弃 - **寄存器冲突**:多次`append`时确保寄存器使用不冲突(如复用`v1`存放临时值) 通过分析`StringBuilder.append`的调用链,可准确还原原始代码的字符串拼接逻辑。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值