这篇文章讲解Java代码的基本执行过程
我们先抛开各种JAVA IDE,开发工具,只使用文本编辑器,以突出最本质的东西。
在Linux环境下,我们编辑一个文件:
vim HelloWorld.java
编辑如下代码:
1 public class HelloWorld{ 2 String name; 3 public HelloWorld(String name){ 4 this.name = name; 5 } 6 public void pHelloWorld(){ 7 System.out.print("HellWorld," + this.name + "\n"); 8 } 9 public static void main(String []args){ 10 HelloWorld test = new HelloWorld("Lee"); 11 test.pHelloWorld(); 12 } 13 }
想了解这段代码含义请移步这里。
此时这段代码只是一个保存于文件中的字符串,这个文件 HelloWorld.java就称为源程序。
JAVA代码的执行过程如下图(其实很多解释型语言如Python的代码执行机制也类似):
首先在shell中执行:
javac HelloWorld.java
此时将保存着字符串的源程序HelloWorld.java编译成了可由java解释器理解的字节码HelloWorld.class.
下面将该字节码交由解释器运行,执行:
java HelloWorld
结果:
在这里解释一下字节码的概念。
对于C/C++这种语言,编译的时候编译器直接将字符串代码编译成了可交由操作系统直接运行的二进制码.
而对于JAVA,Python这类语言,他们的编译器是先将字符串码翻译成了可交由JAVA/Python解释器运行的字节码,真正运行时是解释器将这些字节码翻译成操作系统认识的二进制码。
下面是对字符串代码,字节码,二进制码的形象体现。
字符串码:
字符串码给人类看。
public class HelloWorld{ String name; public HelloWorld(String name){ this.name = name; } public void pHelloWorld(){ System.out.print("HellWorld," + this.name + "\n"); } public static void main(String []args){ HelloWorld test = new HelloWorld("Lee"); test.pHelloWorld(); } }
字节码:
javap -c 可以将java字节码比较形象的显示出来,每一列的第一个数字代表字节码的执行地址编号。
从上往下读就是解释器执行代码的过程。
字节码给java解释器看。
[[email protected]192 workspace]$ javap -c HelloWorld.class Compiled from "HelloWorld.java" public class HelloWorld { java.lang.String name; public HelloWorld(java.lang.String); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: aload_1 6: putfield #2 // Field name:Ljava/lang/String; 9: return public void pHelloWorld(); Code: 0: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 3: new #4 // class java/lang/StringBuilder 6: dup 7: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V 10: ldc #6 // String HellWorld, 12: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 15: aload_0 16: getfield #2 // Field name:Ljava/lang/String; 19: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 22: ldc #8 // String \n 24: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 27: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 30: invokevirtual #10 // Method java/io/PrintStream.print:(Ljava/lang/String;)V 33: return public static void main(java.lang.String[]); Code: 0: new #11 // class HelloWorld 3: dup 4: ldc #12 // String Lee 6: invokespecial #13 // Method "<init>":(Ljava/lang/String;)V 9: astore_1 10: aload_1 11: invokevirtual #14 // Method pHelloWorld:()V 14: return }
二进制码:
二进制码就是经过解释器解释的字节码,可以直接交由操作系统、CPU执行。
查看Linux的bin目录下的ls文件(对应ls指令的代码)的二进制码:
[[email protected]192 bin]$ hexdump ls | more 0000000 457f 464c 0102 0001 0000 0000 0000 0000 0000010 0002 003e 0001 0000 4b48 0040 0000 0000 0000020 0040 0000 0000 0000 c418 0001 0000 0000 0000030 0000 0000 0040 0038 0009 0040 001e 001d 0000040 0006 0000 0005 0000 0040 0000 0000 0000 0000050 0040 0040 0000 0000 0040 0040 0000 0000......
上面是二进制码的16进制表示。比如45表示二进制01000101。
附:代码解释
HelloWorld.java
1 public class HelloWorld{ 2 String name; 3 public HelloWorld(String name){ 4 this.name = name; 5 } 6 public void pHelloWorld(){ 7 System.out.print("HellWorld," + this.name + "\n"); 8 } 9 public static void main(String []args){ 10 HelloWorld test = new HelloWorld("Lee"); 11 test.pHelloWorld(); 12 } 13 }
第1行代码建立一个公有类HelloWorld
Java要求每个文件中只能有一个public类,且该公有类的类名必须与文件名一致。
比如这个文件名为HelloWorld.java,那么必须为public class HelloWorld ,其他的都不行 。
如果使用eclipse开发,当你建好一个.java文件时,eclipse会自动为你使用文件名添加公有类的代码。
第2行声明了一个String类型的变量name。
第3-5行定义了类的构造函数。
构造函数是在这个类实例化的时候默认自动调用的函数。构造函数不是必须去定义,如果没有定义,java会调用一个默认的构造函数。
Java定义构造函数就是定义一个与类名同名的方法,且无返回值。
this.name中的this指代这个类实例化后的实例。
比如在第10行我在实例化这个类时将实例取名为test,那么this=test,this.name=test.name.
在这里多说一点,其实一个类中的每一个方法(函数)都有一个默认参数this,比如:
public void test() 相当于 public void test(this)
这个this是在编译器编译到字节码的时候由编译器自己加上去的,均指代类实例化后那个实例。
第6-8行定义了类的一个方法,叫函数也可以。void表示这个函数的返回类型,没有就是void。
如果一个函数有返回值,那么必须将函数返回类型定义成返回值的类型,如:
1 public int test(){ 2 return 1 3 } 4 5 public String test1(){ 6 return "Hello,World" 7 }
第9-12行则是定义了一个main函数,main函数是java文件执行的入口。
这个main函数在这个public类中唯一,也在这个文件中唯一。
第10行将类进行实例化。
java使用new关键字将一个类实例化。左侧的HelloWorld表示这个test变量的类型是HelloWorld类,=号右侧将HelloWorld类实例化并赋给test.
第11行调用实例的方法pHelloWorld.Java中的方法调用直接使用符号"."即可,与python一样。
其实python和java有好多相似的地方。或者说各种语言之间都有许多共同点。精通了一门语言,学其他的语言就会事半功倍。
如果上面的描述有误欢迎在评论中指出,因为我也是开始学习不久。