编译
将便于人编写、阅读、维护的高级计算机语言所写作的源代码程序,翻译为计算机能解读、运行的低阶机器语言的程序的过程就是编译。负责这一过程的处理的工具叫做编译器。
- 不同的语言都有自己的编译器,Java语言中负责编译的编译器是一个命令:javac(JDK中的Java语言编译器)
反编译
反编译的过程与编译刚好相反,就是将已编译好的编程语言还原到未编译的状态,也就是找出程序语言的源代码。Java语言中的反编译一般指将class文件转换成java文件。
-
反编译工具
1、javap
javap是jdk自带的一个工具,可以对代码反编译,也可以查看java编译器生成的字节码。
例:分析Java 7中的switch是如何支持String的
源代码:
public class Demo {
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 Demo.java
javap -c Demo.class
生成代码
Compiled from "Demo.java"
public class road.test.Demo {
public road.test.Demo();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #16 // String world
2: astore_1
3: aload_1
4: dup
5: astore_2
6: invokevirtual #18 // Method java/lang/String.hashCode:()I
9: lookupswitch { // 2
99162322: 36
113318802: 48
default: 82
}
36: aload_2
37: ldc #24 // String hello
39: invokevirtual #26 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
42: ifne 60
45: goto 82
48: aload_2
49: ldc #16 // String world
51: invokevirtual #26 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
54: ifne 71
57: goto 82
60: getstatic #30 // Field java/lang/System.out:Ljava/io/PrintStream;
63: ldc #24 // String hello
65: invokevirtual #36 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
68: goto 82
71: getstatic #30 // Field java/lang/System.out:Ljava/io/PrintStream;
74: ldc #16 // String world
76: invokevirtual #36 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
79: goto 82
82: return
}
2、jd-gui
通过反编译工具jd-gui反编译.class文件
public class Demo
{
public static void main(String[] args)
{
String str = "world";
String str1;
switch ((str1 = str).hashCode())
{
case 99162322:
if (str1.equals("hello")) {
break;
}
break;
case 113318802:
if (!str1.equals("world"))
{
return;System.out.println("hello");
}
else
{
System.out.println("world");
}
break;
}
}
}
通过这个工具就很清楚的可以看到原来字符串的switch是通过equals()和hashCode()方法来实现的,switch中只能使用整型,而hashCode()方法返回的刚好是int,所以swich只支持一种数据类型,那就是整型,其他数据类型都是转换成整型之后在使用switch的。
javap
用于反编译和查看编译器编译后的字节码。其中javap -c用于列出每个方法所执行的JVM指令,并显示每个方法的字节码的实际作用。
用法:
-help 帮助
-l 输出行和变量的表
-public 只输出public方法和域
-protected 只输出public和protected类和成员
-package 只输出包,public和protected类和成员,这是默认的
-p -private 输出所有类和成员
-s 输出内部类型签名
-c 输出分解后的代码,例如,类中每一个方法内,包含java字节码的指令,
-verbose 输出栈大小,方法参数的个数
-constants 输出静态final常量
java 10中的var
语法糖
指在计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。
本地变量类型推断
一种语法糖,为了方便和简化开发,Java 10将提供一个新的语法糖——本地变量类型推断。它并不是Java语言独有的特性,许多流行的编程语言,比如C++, C#以及Go,在定义过程中,都提供一种局部变量类型推断的功能。
源代码
public class Demo {
public static void main(String[] args) {
// 初始化局部变量
var string = "HardWJJ";
// 初始化局部变量
var stringList = new ArrayList<String>();
stringList.add("Hard");
stringList.add("WJJ");
// 增强for循环的索引
for (var s : stringList) {
System.out.println(s);
}
// 传统for循环的局部变量定义
for (var i = 0; i < stringList.size(); i++) {
System.out.println(stringList.get(i));
}
}
}
运行以下命令
D:\Program Files\Java\jdk-10.0.2\bin>javac E:\workspace\sts\road\src\road\test\Demo.java
使用反编译工具查看编译后的.class
import java.io.PrintStream;
import java.util.ArrayList;
public class Demo {
public static void main(String[] arrstring) {
String string = "HardWJJ";
ArrayList<String> arrayList = new ArrayList<String>();
arrayList.add("Hard");
arrayList.add("WJJ");
for (String string2 : arrayList) {
System.out.println(string2);
}
for (int i = 0; i < arrayList.size(); ++i) {
System.out.println((String)arrayList.get(i));
}
}
}
代码对应关系
本地变量类型推断写法 | 正常写法 |
---|---|
var string = “HardWJJ”; | String string = “HardWJJ”; |
var stringList = new ArrayList(); | ArrayList arrayList= new ArrayList(); |
for (var s : stringList) | for (String string2 : arrayList) |
for (var i = 0; i < stringList.size(); i++) | for (int i = 0; i < arrayList.size(); i++) |
和JavaScript的区别
- JavaScript 是一种弱类型(或称动态类型)语言,即变量的类型是不确定的。可以用“4”-3这样的语法,进行字符串和数字的运算。
- Java依然它还是一种强类型的语言。通过上面反编译的代码,最终在编译之后还是要将var定义的对象类型定义成编译器推断出来的类型的。
网友评论