为什么原始代码和编译代码之间存在差异

时间:2011-03-20 12:19:22

标签: java decompiling

这里我尝试编译java文件,我使用java反编译器来检查已编译的代码。为什么char被转换为int并且一些变量名也改变了?

原始JAVA文件

class CharacterTest{
public static void main(String[] args){

    char t=140; 
    char f='t';
    char p='t';
    System.out.print(t);

}
}

编译代码

import java.io.PrintStream;

class CharacterTest
{
public static void main(String[] paramArrayOfString)
{
char c = '';
int i = 116;
int j = 116;
System.out.print(c);
}
}

4 个答案:

答案 0 :(得分:2)

JVM和字节码本身不区分char和int。这只是在语义/语言层面。

第二个局部变量名不包含在类文件中。因此反编译器必须发明自己的名字。

答案 1 :(得分:1)

完全取决于反编译器的实现细节。反编译器不知道局部变量的名称和类型,因此必须使用一些启发式方法从字节码重构它。

您的字节码如下所示:

   0:   sipush  140   
   3:   istore_1      
   4:   bipush  116   
   6:   istore_2      
   7:   bipush  116   
   9:   istore_3      

正如您所看到的,140被视为short类型的常量,而116被视为byte类型的常量(它是由以下事实引起的: 116适合签名字节,但140不符合。

现在反编译器试图猜测它在源代码中意味着什么。看起来反编译器将常量类型的差异视为局部变量类型的差异(也可以使用编译器选择的print()签名作为提示来确定t的类型)和变量名称的生成取决于类型(c的{​​{1}},char的{​​{1}}和i的{​​{1}}。

另见:

答案 2 :(得分:0)

char实际上是Integer类型。

char类型(一个字符)包含一个16位Unicode字符,实际上由无符号的16位整数表示。

(来源:Kathy Sierra的SCJP)

关于命名更改,我不确定。但我想这是你的反编译器的一个问题。您是否尝试过不同的反编译器并查看每个人都生成的变量名称?

答案 3 :(得分:0)

如上所述,VM的局部变量只能包含类型(或更确切地说,可以通过命令访问)intlongfloat,{{1} }和引用 - 所以所有整数类型(除了long)都在内部被视为double

第一个变量仍为int,因为这是此处调用的char方法的参数类型,因此编译器有一些方法可以猜测它,而其他两个变量不再使用,所以他们留在println()