1. 程式人生 > >java入門學習筆記之1(類的定義,代碼的編譯執行)

java入門學習筆記之1(類的定義,代碼的編譯執行)

spa hex nts 自動調用 [] alt vim 進制 技術

這篇文章講解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解釋器看。

[lijianyang@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指令的代碼)的二進制碼:

[lijianyang@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有好多相似的地方。或者說各種語言之間都有許多共同點。精通了一門語言,學其他的語言就會事半功倍。

如果上面的描述有誤歡迎在評論中指出,因為我也是開始學習不久。

java入門學習筆記之1(類的定義,代碼的編譯執行)