机器语言(Machine Language)和汇编语言(Assembly Language)属于低级语言,直接用计算机指令编写程序。
Java等属于高级语言,用语句(Statement)编写程序,语句是计算机指令的抽象表示。
什么是编译
可以这样简单的理解:低级语言是计算机认识的语言、高级语言是程序员认识的语言。
那么如何从高级语言转换成低级语言呢?这个过程其实就是编译。
eg: 一条a=b+1
;语句要翻译成三条汇编或机器指令,这个过程称为编译(Compile),由编译器(Compiler)来完成。
编译器?Java语言中负责编译的编译器是一个命令:javac
当我们写完一个HelloWorld.java
文件后,我们可以使用javac HelloWorld.java
命令来生成HelloWorld.class
文件,这个class
类型的文件是JVM可以识别的文件。通常我们认为这个过程叫做Java语言的编译。其实,class
文件仍然不是机器能够识别的语言,因为机器只能识别机器语言,还需要JVM再将这种class
文件类型字节码转换成机器可以识别的机器语言。
什么是反编译
反编译的过程与编译刚好相反,就是将已编译好的编程语言还原到未编译的状态,也就是找出程序语言的源代码。
Java反编译工具
java的反编译主要工具:javap、jad和cfr
javap
javap
是jdk自带的一个工具,可以对代码反编译,也可以查看java编译器生成的字节码。
public class SwichOfStr {
public static void main(String[] args) {
String str = "world";
switch (str) {
case "hello":
System.out.println("hello");
break;
case "world":
System.out.println("world");
break;
default:
break;
}
}
}
执行以下两个命令:
javac switchOfStr.java
javap -c switchOfStr.class
生成代码如下:
Compiled from "SwichOfStr.java"
public class com.demo.config.SwichOfStr {
public com.demo.config.SwichOfStr();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String world
2: astore_1
3: aload_1
4: astore_2
5: iconst_m1
6: istore_3
7: aload_2
8: invokevirtual #3 // Method java/lang/String.hashCode:()I
11: lookupswitch { // 2
99162322: 36
113318802: 50
default: 61
}
36: aload_2
37: ldc #4 // String hello
39: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
42: ifeq 61
45: iconst_0
46: istore_3
47: goto 61
50: aload_2
51: ldc #2 // String world
53: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
56: ifeq 61
59: iconst_1
60: istore_3
61: iload_3
62: lookupswitch { // 2
0: 88
1: 99
default: 110
}
88: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
91: ldc #4 // String hello
93: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
96: goto 110
99: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
102: ldc #2 // String world
104: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
107: goto 110
110: return
}
大致的意思就是把String转成hashcode,然后进行比较。
jad
jad是一个比较不错的反编译工具,只要下载一个执行工具,就可以实现对class
文件的反编译了。还是上面的源代码,使用jad反编译后内容如下:
命令:jad switchOfStr.class
public class switchOfStr
{
public switchOfStr()
{
}
public static void main(String args[])
{
String str = "world";
String s;
switch((s = str).hashCode())
{
default:
break;
case 99162322:
if(s.equals("hello"))
System.out.println("hello");
break;
case 113318802:
if(s.equals("world"))
System.out.println("world");
break;
}
}
}
可以看到原来字符串的switch是通过equals()
和hashCode()
方法来实现的。
CFR
命令:
java -jar cfr_0_125.jar switchOfStr.class --decodestringswitch false
得到以下代码:
public class switchOfStr {
public static void main(String[] arrstring) {
String string;
String string2 = string = "world";
int n = -1;
switch (string2.hashCode()) {
case 99162322: {
if (!string2.equals("hello")) break;
n = 0;
break;
}
case 113318802: {
if (!string2.equals("world")) break;
n = 1;
}
}
switch (n) {
case 0: {
System.out.println("hello");
break;
}
case 1: {
System.out.println("world");
break;
}
}
}
}
通过这段代码也能得到字符串的switch是通过equals()
和hashCode()
方法来实现的结论。