1. 程式人生 > >Java入門記(一):折騰HelloWorld

Java入門記(一):折騰HelloWorld

  HelloWorld,學習每門語言的第一步。有人戲稱,這些年的程式設計生涯就是學習各種語言的HelloWorld,不知是自謙還是自嘲。目前所在的公司使用Java作為主要開發語言,我進行語言轉換也大半年了,這HelloWorld便是語言轉換的第一關。好在本科的時候學過那麼一點,而且在此之前進行了較長時間的C/C++開發,其間有不少的相似之處。這裡略去JDK的安裝和環境配置(JDK為1.6.0.45),直接從程式碼入手。

  首先看一個最簡單的Java下的HelloWorld:

public class HelloWorld {
  public static void main(String[]agrs)
    {
      System.out.println(
"HelloWorld!"); } }

  一般來說,初學者寫HelloWorld到這裡,編譯完執行一下看到結果就可以結束了。下面對這個小程式進行更多的探索,進一步瞭解和學習Java程式設計中的特性。

1.原始碼檔案的編碼

  最初為了簡單起見,我是在Win7中用記事本編寫並儲存程式碼為HelloWorld.java,然後用命令列直接javac編譯。出於在Windows下寫Linux程式的習慣,我在記事本儲存時將程式碼儲存為UTF-8編碼的HelloWorld.java檔案。編譯時提示:

  在仔細檢查原始碼確定沒有任何拼寫錯誤後,嘗試將編碼改回Windows預設的ANSI,成功生成了HelloWorld.class並能夠正確執行,看來是編碼不一致惹得禍。接下來,抱著嘗試的心態,使用Unicode和Unicode Big Endian儲存原始碼,發現也會報錯,只是提示不同,編譯器提示有非法字元。這個問題如果在Eclipse中用預設方式儲存檔案,則不會出現。

  有趣的是,如果使用Java的I/O方法生成文字檔案,應該如何確定檔案的編碼,也是一個常見的問題。如果僅僅是涉及Windows/Linux兩個平臺之間的編碼差異,而不包括中文編碼,前者使用\r\n,而後者使用\n\r或\n即可。對於漢字編碼,需要在使用到的I/O方法中指定編碼,這裡不再做一步的詳述。

2.為什麼沒有import語句?

  還記得經典的K&R中經典的HelloWorld麼?即使極盡精簡,C中仍然避免不了使用#include <stdio.h>來引入標頭檔案,才能使用printf函式。

  而Java和C/C++不一樣,這個簡單的HelloWorld不需要類似include的import,也不需要使用名稱空間,看似更簡單了些。實際上,這是因為Java給每個Java檔案都預設匯入了java.lang這個包,從而省去了import java.lang;這個語句罷了。這樣,下面進行螢幕輸出直接使用System.out.println()即可。

  java.lang中包括的都是常用的類和方法,具體內容讀者有興趣可以自行查閱。上文提到java.import是“預設匯入”,有沒有什麼辦法禁止其匯入?我搜索了下,目前還沒有查到相關的資料,如果哪位讀者瞭解,希望能告訴我。(這可能涉及到類載入器的問題,暫未進行研究)

  如果你執意在這段簡單的程式碼中使用與import對應的package,可以參考本文第六節

3.檔名為什麼要與類名一致?類名與修飾符問題

  在實踐中可以看出,編譯結果是HelloWorld.class,但是執行的命令卻是java HelloWorld。如果這個檔案還有更多的類,可以看到這些類在編譯時都生成了*.class檔案。對於“類名和檔名一致”這個疑問提的並不合理,顯然程式碼編寫時,一個檔案中可以有很多個類。這涉及到了Java的特性(來自《Java程式設計思想(第四版中文版)》):

每個編譯單元(檔案)只能最多有一個public類;如果有,其名稱必須與含有這個編譯單元的檔名相匹配,包括大小寫。

  如果不遵守這個要求,寫出類似下面的程式碼

//ERROR IN CODE
public class HelloWorld {
  public static void main(String[]agrs)
    {
      System.out.println("HelloWorld!");
    }
}

public class HelloWorld2 {
  public static void main(String[]agrs)
    {
      System.out.println("HelloWorld, me too!");
    }
}

  那麼編譯器會提示這一點

  如果把HelloWorld2類的public去掉,將使其變成包訪問許可權,程式可以正常執行,此時只執行HelloWorld.main(),並不會發生衝突。

  實際上,如果這個檔案只有一個HelloWorld類,或者有兩個類,只要這個包括main()的類名與檔名一致,類名前不加public也是可以正常執行的,且呼叫的是與檔名一致的類的main()方法。但個人認為這不是良好的程式設計實踐,如下:

class HelloWorld {
  public static void main(String[]agrs)
    {
      System.out.println("HelloWorld!");
    }
}

class HelloWorld2 {
  public static void main(String[]agrs)
    {
      System.out.println("HelloWorld, me too!");
    }
}

   編譯時將生成HelloWorld.class和HelloWorld2.class,分別執行時,結果為兩個類各自的main()方法。

4.main()函式的引數表和修飾符

  在C中,對於main()的修飾符和引數表有著很多細節要注意(可以參考五花八門的main())。對於Java,這裡對main()的寫法也進行簡單的探究。

  先來看引數表String args[]。雖說編譯器要求必須是這種形式,但如果不用標準形式而用其他形式如int x、String s作為引數表,編譯是可以通過的,但是在執行時則會丟擲異常,無論是否提供了引數:

  NoSuchMethodError表名,期望的是引數為String args[]的main()方法。雖然提供了同名方法,由於方法的過載機制,並不能代替期望的main(String args[])方法。

  接下來看修飾符public。在第3條已經提到了public對於類名的修飾有所說明,而對於main()這個與檔案同名的類的成員方法,為了能被呼叫,只能用public修飾。不使用修飾符(包訪問許可權)、使用private或protected都會提示:

  對於修飾符static,表明這個方法是在儲存在靜態儲存區的,不需要例項化物件就可以呼叫。去掉static後,可以編譯通過,執行時提示

為了進一步驗證這一點,可以編寫構造方法來驗證。(構造方法是在類的物件在例項化時會被呼叫的方法)

public class HelloWorld {
    HelloWrold
    {
        System.out.println("Constructor");
    }
    public static void main(String[]agrs)
    {
      System.out.println("HelloWorld!");
    }
}

  編譯執行時,可以看到構造方法並沒有執行。

  對於修飾符void,也是必須的。改成int等並加上對應的return語句同樣會提示“NoSuchMethodError: main”。在《Java虛擬機器規範(JavaSE7)》(周志明等譯)中介紹到

Java虛擬機器的啟動是通過引導類載入器(Bootstrap Class Loader §5.3.1)建立一個初始類(Initial Class)來完成,這個類是由虛擬機器的具體實現指定。緊接著,Java虛擬機器連結這個初始類,初始化並呼叫它的public void main(String[])方法。之後的整個執行過程都是由對此方法的呼叫開始。

  可見,void返回值也是被要求的,其他形式是不允許的。

  經過進一步的測試可知,args[0]是第一個引數;而在C中,argv[0]是執行的程式名。 

5.既然main()方法是類方法……

既然main()方法是類方法,那麼在例項化這個類的物件時,自然可以再次呼叫這個方法。對HelloWorld原始碼加對應的兩行,如下所示

public class HelloWorld {
  public static void main(String[] args)
    {
        HelloWorld h = new HelloWorld();
        System.out.println("HelloWorld!");
        h.main(args);
    }
}

執行結果為

HelloWorld!

HelloWorld!

HelloWorld!

... ...
HelloWorld!
Exception in thread "main" java.lang.StackOverflowError
at sun.nio.cs.ext.DoubleByteEncoder.encodeLoop(Unknown Source)
at java.nio.charset.CharsetEncoder.encode(Unknown Source)
at sun.nio.cs.StreamEncoder.implWrite(Unknown Source)
at sun.nio.cs.StreamEncoder.write(Unknown Source)
at java.io.OutputStreamWriter.write(Unknown Source)
at java.io.BufferedWriter.flushBuffer(Unknown Source)
at java.io.PrintStream.write(Unknown Source)
at java.io.PrintStream.print(Unknown Source)
at java.io.PrintStream.println(Unknown Source)
at main.HelloWorld.main(HelloWorld.java:15)
at main.HelloWorld.main(HelloWorld.java:16)
at main.HelloWorld.main(HelloWorld.java:16)
at main.HelloWorld.main(HelloWorld.java:16)
... ...

  可見HelloWorld被玩壞了,這個無限遞迴建立物件的過程導致了記憶體溢位。

6.試試package

  當然,使用java更多的時候往往要處理多個檔案。為了組織同一名稱空間下的檔案,需要使用包來進行。對應於import,為了指定當前檔案在哪個包,需要加上package語句。隨便加上一個包名,最初的程式碼變成了

package test;

public class HelloWorld {
  public static void main(String[]agrs)
    {
      System.out.println("HelloWorld!");
    }
}

編譯後,卻無法執行,如下圖所示

  其實,包名是隱含目錄結構的。為了執行,需要把HelloWorld.class移入這個路徑的test資料夾,按照下面的方式執行才可以:

   (2015.10.6更新)如果引用了三方jar包,可以在執行javac和java命令的時候使用-cp指定jar包所在相對路徑,或者直接把jar包放在該class檔案所在目錄或環境變數CLASSPATH指定的目錄下。

小結

  可見,對於一個小小的HelloWorld,還是有不少東西可以發掘,只是限於篇幅和本人水平,本文僅僅進行了簡要的介紹。以下是本文提出的可以在後續學習中繼續深入的主題,僅供參考:

1.I/O方法編碼方式的選擇

2.包和程式碼組織

3.Java虛擬機器(JVM)

相關閱讀

相關推薦

Java入門()折騰HelloWorld

  HelloWorld,學習每門語言的第一步。有人戲稱,這些年的程式設計生涯就是學習各種語言的HelloWorld,不知是自謙還是自嘲。目前所在的公司使用Java作為主要開發語言,我進行語言轉換也大半年了,這HelloWorld便是語言轉換的第一關。好在本科的時候學過那麼一點,而且在此之前進行了較長時間的C

Java入門(二)向上轉型與向下轉型

interface CanFight { void fight(); } interface CanSwim { void swim(); } interface CanFly { void fly(); } class ActionCharacter {

Java入門(四)容器關係的梳理(上)——Collection

      目錄 三、Set   Java.util中的容器又被稱為Java Collections framework。雖然被稱為框架,但是其主要目的是提供一組介面儘量簡單而且相同、並且儘量高效、以便於開發人員按照場景選用,而不

Java入門(三)初始化順序

初始化順序的規則 1.在一個類的物件例項化時,成員變數首先初始化,然後才呼叫構造器,無論書寫順序。如果呼叫構造器前,沒有顯式初始化,那麼會賦預設值。 這樣做法的原因可以理解為:構造器執行時可能會用到一些成員變數的初值。 2.static變數早於所有其他的類成員變數初始化,同樣無論書寫順序。但是stati

Java入門(五)容器關係的梳理(下)——Map

注意:閱讀本文及相關原始碼時,需要資料結構相關知識,包括:雜湊表、連結串列、紅黑樹。   Map是將鍵(key)對映到值(value)的物件。不同的對映不能包含相同的鍵;每個鍵最多隻能對映到一個值。下圖是常見Map的介面和實現。與Collection相比,繼承關係簡單不少。 一、Map介面和Abs

Java入門Hello World !

公司 java入門(一) 擁有 sys 成熟 pos pac runt asc 前言 從今天開始,準備寫Java Web開發的系列文章,畢竟自己主攻的還是Java方向,Python只是業余學習的興趣使然,在第二技能還沒有培養成熟前,做好第一技能的鞏固和提高是很有必要的。從正

SpringBoot入門()HelloWorld開始

從0開始建立springBoot專案,話不多說,跟著我一步一步來就行了。 1.新建專案   1) 建立新專案,選擇project, 點點點就好了        2)  Spring Initializr——>選擇SDK(1.8)—&mda

Java NIO筆記()NIO介紹

事件 .net 數據報 數據類型 單線程 long 處理 哪些 選擇 Java NIO即Java Non-blocking IO(Java非堵塞I/O),由於是在Jdk1.4之後添加的一套新的操作I/O工具包,所以通常會被叫做Java New IO。NI

java工具包日期處理

div 方便 開始 .text simple nor atd blog param 作者:NiceCui 本文謝絕轉載,如需轉載需征得作者本人同意,謝謝。 本文鏈接:http://www.cnblogs.com/NiceCui/p/7846812.html 郵箱:

java入門必學HTML和CSS

java ;入門 ; html; css Java開發已經悄無聲息的走進我們的生活中,無論是手機軟件、手機Java遊戲還是電腦軟件等,只要你使用到電子產品就會碰到和Java有關的東西,更多的企業正采用Java語言開發網站,也吸引了好多誌同道合的朋友開始加入Java開發的行列。 我們知道在

java 進階代理和動態代理

實現 public rgs tostring 開源項目 body llb ack code 靜態代理:   定義頂級接口:Iservice //目標類和代理類都實現該接口 public interface Iservice { public String serv

Java入門第一課資料型別

Java入門第一課:資料型別 文章目錄 Java入門第一課:資料型別 1. 科普類 2.資料型別 2.1整型 2.2浮點型別 2.3 char型別 2.4布林型別 2.5變數

Java的執行機制——有C++基礎的Java入門

前言:還是那句話,第一、凡是涉及到概念性內容的時候,我都會到官網去確認內容的真實性!第二、我喜歡偏向於原理學習。在 java介紹裡面,我認為知道這是一門完全面向物件的語言就足夠了。我的導師說C++是認為程式設計師是很強大的,開放了所有的功能許可權;Java是認為程式設計師不是那麼全能的

Java基礎 實驗簡單資料型別和流程控制

1.實驗目的 掌握識別符號的定義規則、表示式的組成、各種資料型別及其使用方法、各種運算子的使用及其優先順序控制。掌握分支結構,迴圈結構,continue,break,語句標號等內容。 2.實驗內容 (1)輸入一個三角形的3個邊長,檢查是否能構成一個直角三角形。 (2)任意從鍵盤輸入一個0到

Java學習階段2.CSS

目錄 瞭解CSS 五大CSS選擇器 CSS匯入方式   瞭解CSS CSS 概述 CSS 指層疊樣式表 (Cascading Style Sheets) 樣式定義如何顯示 HTML 元素 樣式通常儲存在樣式表中

Java學習階段1.HTML

目錄 瞭解HTML語言 HTML整體結構 字型標籤 表單元素 瞭解HTML語言 什麼是 HTML? HTML 是用來描述網頁的一種語言。 HTML 指的是超文字標記語言 (Hyper Text Markup Language)

Java學習階段3.JavaScript

目錄 瞭解JavaScript JavaScript基本語法 JavaScript內部物件 JavaScript的DOM BOM 自定義函式 全域性函式 事件處理 瞭解JavaScript JavaScript 是指令碼語言 JavaScript 是一

RocketMQ爬坑()安裝使用

1. RocketMQ簡介 RocketMQ作為一款純java、分散式、佇列模型的開源訊息中介軟體(阿里的說法是不遵循任何規範的,所以不能完全用JMS的那一套東西來看它),經歷了淘寶雙十一的洗禮,在功能和效能上據說是遠超ActiveMQ。 RocketMQ簡介,其中

JAVA入門

前言       Java是一門面向物件程式語言,不僅吸收了C++語言的各種優點,還摒棄了C++裡難以理解的多繼承、指標等概念,因此Java語言具有功能強大和簡單易用兩個特徵。Java語言作為靜態面向

JAVA NIO學習NIO簡介、NIO&IO的主要區別

在前面學習了IO之後,今天我們開始進入NIO學習環節,首先我們會NIO做一個簡單的介紹,讓大家認識NIO,然後會和IO進行一個對比認識進行區分。好了,下面我們就開始學習: 一、NIO簡介 1.概述 從JDK1.4開始,Java提供了一系列改進的輸入/輸出處理的新特性,被統稱為NIO(即N