日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

java程序设计_80后程序员,带你深入理解Java基本的程序设计结构,不来你别后悔...

發(fā)布時(shí)間:2025/3/19 java 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java程序设计_80后程序员,带你深入理解Java基本的程序设计结构,不来你别后悔... 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

現(xiàn)在,假定已經(jīng)成功地安裝了JDK,并且能夠運(yùn)行第2章中給出的示例程序。從現(xiàn)在開(kāi)始將介紹Java應(yīng)用程序設(shè)計(jì)。本章主要講述程序設(shè)計(jì)相關(guān)的基本概念(如數(shù)據(jù)類型、分支以及循環(huán))在Java中的實(shí)現(xiàn)方式。

非常遺憾,需要告誡大家,使用Java編寫(xiě)GUI應(yīng)用程序并不是一件很容易的事情,它需要編程者掌握很多相關(guān)的知識(shí)才能夠創(chuàng)建窗口、添加文本框和按鈕等。而基于GUI的Java應(yīng)用程序設(shè)計(jì)技術(shù)與本章將要介紹的程序設(shè)計(jì)基本概念相差甚遠(yuǎn),因此在本章中給出的所有例子都是旨在說(shuō)明一些相關(guān)概念而設(shè)計(jì)的“玩具式”程序,它們僅僅通過(guò)shell窗口輸入輸出。

最后需要說(shuō)明,對(duì)于一個(gè)具有使用C++經(jīng)驗(yàn)的程序員來(lái)說(shuō),這一章的內(nèi)容只需要瀏覽一下,應(yīng)該重點(diǎn)閱讀分布在正文中的C/C++注釋。而對(duì)于具有使用Visual Basic等其他編程背景的程序員來(lái)說(shuō),可能會(huì)發(fā)現(xiàn)其中的絕大多數(shù)概念都很熟悉,只是在語(yǔ)法上有比較大的差異,因此,需要非常仔細(xì)地閱讀本章的內(nèi)容。

一個(gè)簡(jiǎn)單的Java應(yīng)用程序

下面看一個(gè)最簡(jiǎn)單的Java應(yīng)用程序,它只發(fā)送一條消息到控制臺(tái)窗口中:

這個(gè)程序雖然很簡(jiǎn)單,但因?yàn)樗械腏ava應(yīng)用程序都具有這種結(jié)構(gòu),所以值得花一些時(shí)間對(duì)它進(jìn)行研究。首先,Java對(duì)大小寫(xiě)敏感。如果出現(xiàn)了大小寫(xiě)拼寫(xiě)錯(cuò)誤(例如,將main拼寫(xiě)成了Main),程序就無(wú)法運(yùn)行。

下面逐行地查看一下這段源代碼。關(guān)鍵字public被稱為訪問(wèn)修飾符(access modifier),它用于控制程序的其他部分對(duì)這段代碼的訪問(wèn)級(jí)別。在第5章中將會(huì)更加詳細(xì)地介紹訪問(wèn)修飾符的具體內(nèi)容。關(guān)鍵字class表明Java程序中的全部?jī)?nèi)容都包含在類中。這里,只需要將類作為一個(gè)加載程序邏輯的容器,程序邏輯定義了應(yīng)用程序的行為,在下一章中將會(huì)用大量的篇幅介紹Java類。

正如第1章所述,類是構(gòu)建所有Java應(yīng)用程序和applet的構(gòu)建塊。Java應(yīng)用程序中的全部?jī)?nèi)容都必須放置在類中。

關(guān)鍵字class后面緊跟類名。Java中定義類名的規(guī)則很寬松。名字必須以字母開(kāi)頭,后面可以跟字母和數(shù)字的任意組合。長(zhǎng)度基本上沒(méi)有限制。但是不能使用Java保留字(比如public或class)作為類名。(保留字列表請(qǐng)參閱附錄A。)

從類名FirstSample可以看出,標(biāo)準(zhǔn)的命名規(guī)范為:類名是以大寫(xiě)字母開(kāi)頭的名詞。如果名字由多個(gè)單詞組成,每個(gè)單詞的第一個(gè)字母都應(yīng)該為大寫(xiě)。(這種在一個(gè)單詞間使用大寫(xiě)字母的方式被稱為“camel case”,以它自己為例,應(yīng)該寫(xiě)成“CamelCase”。)

源代碼的文件名必須與公有類的名字相同,并用.java作為擴(kuò)展名。因此,存儲(chǔ)這段源代碼的文件名必須為FirstSample.java。(再次提醒大家注意,大小寫(xiě)是非常重要的,千萬(wàn)不能寫(xiě)成firstsample.java。)

如果已經(jīng)正確地命名了這個(gè)文件,并且源代碼中沒(méi)有任何錄入錯(cuò)誤,那么在編譯這段源代碼之后,就會(huì)得到一個(gè)包含該類字節(jié)碼的文件。Java編譯器將字節(jié)碼文件自動(dòng)地命名為FirstSample.class,并與源文件存儲(chǔ)在同一個(gè)目錄下。最后,使用下面這行命令運(yùn)行這個(gè)程序:

java FirstSample

(請(qǐng)記住,不要添加.class擴(kuò)展名。)程序執(zhí)行之后,控制臺(tái)上將會(huì)顯示“We will not use

‘Hello,World’!”。

當(dāng)使用

java ClassName

運(yùn)行編譯程序時(shí),Java虛擬機(jī)將從指定類中的main方法開(kāi)始執(zhí)行,因此為了代碼能夠得到執(zhí)行,在類的源文件中必須包含一個(gè)main方法。當(dāng)然,也可以把用戶自定義的方法添加到類中,并且在main方法中調(diào)用它們。(下一章,將講述如何自己定義方法。)

其解決方案放到網(wǎng)上讓所有人監(jiān)督檢查,這是一種非常了不起的舉動(dòng)。“bug 展示”對(duì)程序員來(lái)說(shuō)是一種十分有用的資源,甚至程序員可以對(duì)感興趣的bug進(jìn)行“投票”。得票多的bug在下一個(gè)將發(fā)行的版本的JDK中得到解決的可能性就大。

需要注意源代碼中的括號(hào){ }。在Java中,像在C/C++中一樣,用花括號(hào)劃分程序的各個(gè)部分(通常稱為塊)。Java中任何方法的代碼都用“{”開(kāi)始,用“}”結(jié)束。

花括號(hào)的使用風(fēng)格曾經(jīng)引發(fā)過(guò)許多無(wú)謂的爭(zhēng)論。我們的習(xí)慣是把匹配的花括號(hào)上下對(duì)齊。

不過(guò),由于空白符會(huì)被Java編譯器忽略,所以自然可以選用任何自己喜歡的風(fēng)格。在下面講述各種循環(huán)語(yǔ)句時(shí),我們還會(huì)詳細(xì)地介紹花括號(hào)的使用。

我們暫且不去理睬關(guān)鍵字static void,而僅把它們當(dāng)作編譯Java應(yīng)用程序必需的一部分就行了。

學(xué)習(xí)完第4章,這些內(nèi)容的作用就會(huì)被揭曉。現(xiàn)在需要記住:每個(gè)Java應(yīng)用程序都必須有一個(gè)main方法,其格式如下所示:

接下來(lái),讓我們研究一下這段代碼:

{System.out.println("We will not use 'Hello, World!'");}

一對(duì)花括號(hào)表示方法體的開(kāi)始與結(jié)束,在這個(gè)方法中只包含一條語(yǔ)句。與大多數(shù)程序設(shè)計(jì)語(yǔ)言一樣,可以將Java語(yǔ)句看成是這種語(yǔ)言的句子。在Java中,每個(gè)句子必須用分號(hào)結(jié)束。特別要說(shuō)明一點(diǎn),回車不是語(yǔ)句的結(jié)束標(biāo)志,因此,如果需要可以將一條語(yǔ)句寫(xiě)在多行上。

在上面這個(gè)main方法體中只包含了一條語(yǔ)句,其功能是:將一個(gè)文本行輸出到控制臺(tái)上。

在這里,使用了System.out對(duì)象并調(diào)用了它的println方法。注意,點(diǎn)號(hào)用來(lái)調(diào)用一個(gè)方法。

Java使用的通用語(yǔ)法是

object.method( parameters)

這等價(jià)于函數(shù)調(diào)用。

在這個(gè)例子中,調(diào)用了println方法并傳遞給它一個(gè)字符串參數(shù)。這個(gè)方法將傳遞給它的字符串參數(shù)顯示在控制臺(tái)上。然后,終止這個(gè)輸出行,以便每次調(diào)用println都會(huì)在新的一行上顯示輸出。需要注意一點(diǎn),Java與C/C++一樣,都采用雙引號(hào)分隔字符串。本章稍后將會(huì)詳細(xì)地講解有關(guān)字符串的知識(shí)。

與其他程序設(shè)計(jì)語(yǔ)言一樣,在Java的方法中,可以沒(méi)有參數(shù),也可以有零個(gè)、一個(gè)或多個(gè)參數(shù)。(有的程序員把參數(shù)叫做變?cè)?對(duì)于一個(gè)方法,即使沒(méi)有參數(shù)也需要書(shū)寫(xiě)圓括號(hào)。例如,不帶參數(shù)的println方法只打印一個(gè)空行。使用下面的語(yǔ)句:

System.out.println( );

注釋

與大多數(shù)程序設(shè)計(jì)語(yǔ)言一樣,Java中的注釋也不會(huì)出現(xiàn)在可執(zhí)行程序中。因此,可以在源程序中添加任意多的注釋,而不必?fù)?dān)心可執(zhí)行代碼會(huì)膨脹。在Java中,有三種表示注釋的方式。最常用的方式是使用 //,其注釋內(nèi)容從 // 開(kāi)始到本行結(jié)尾。

System.out.println("We will not use 'Hello, World!'"); //is this too cute?

當(dāng)需要比較長(zhǎng)的注釋時(shí),可以在每行的注釋前面標(biāo)記 //,也可以使用 /* 和 */ 將一段比較長(zhǎng)的注釋括起來(lái)。請(qǐng)參看例3-1。

例3-1 FirstSample.java

第三種注釋可以用來(lái)自動(dòng)地生成文檔。這種注釋以 /**開(kāi)始,以 */ 結(jié)束。有關(guān)這種注釋的詳細(xì)內(nèi)容和自動(dòng)生成文檔的具體方法請(qǐng)參閱第4章。

數(shù)據(jù)類型

Java是一種強(qiáng)類型語(yǔ)言(strongly typed language)。這就意味著必須為每一個(gè)變量聲明一種類型。在Java中,一共有8種基本類型(primitive type),其中有4個(gè)整型、2個(gè)浮點(diǎn)類型、1個(gè)用于表示Unicode編碼的字符單元的字符類型char(請(qǐng)參見(jiàn)論述char類型的章節(jié))和1個(gè)用于表示真值的boolean類型。

整型

整型用于表示沒(méi)有小數(shù)部分的數(shù)值,它允許是負(fù)數(shù)。Java提供了4種整型,具體內(nèi)容如表3-1所示。

在通常情況下,int類型非常有用,但要表示星球上的居住人數(shù),就要使用long類型了。byte和short類型主要用于特定的場(chǎng)合,例如,底層的文件處理或者需要控制占用存儲(chǔ)空間量的大數(shù)組。

在Java中,整型的范圍與運(yùn)行Java代碼的機(jī)器無(wú)關(guān)。這就解決了軟件從一個(gè)平臺(tái)移植到另一個(gè)平臺(tái),或者在同一個(gè)平臺(tái)中的不同操作系統(tǒng)之間進(jìn)行移植給程序員帶來(lái)的諸多問(wèn)題。與此相反,C和C++程序需要針對(duì)不同的處理器選擇最為有效的整型,這樣就有可能造成一個(gè)在32位處理器上運(yùn)行很好的C程序在16位系統(tǒng)上運(yùn)行卻發(fā)生整數(shù)溢出。由于Java程序必須保證在所有機(jī)器上都能夠得到相同的運(yùn)行結(jié)果,所以每一種數(shù)據(jù)類型的取值范圍必須固定。

長(zhǎng)整型數(shù)值有一個(gè)后綴L(如4000000000L)。十六進(jìn)制數(shù)值有一個(gè)前綴0x(如0xCAFE)。八進(jìn)制有一個(gè)前綴0,例如,010對(duì)應(yīng)八進(jìn)制中的8。很顯然,八進(jìn)制表示法比較容易混淆,所以建議最好不要使用八進(jìn)制常數(shù)。

浮點(diǎn)型

浮點(diǎn)類型用于表示有小數(shù)部分的數(shù)值。在Java中有兩種浮點(diǎn)類型,具體內(nèi)容如表3-2所示。

double表示這種類型的數(shù)值精度是float類型的兩倍。(有人稱之為雙精度。)絕大部分應(yīng)用程序都采用double類型。在很多情況下,float類型的精度很難滿足需求。例如,用7位有效數(shù)字足以精確表示普通雇員的年薪,但表示公司總裁的年薪可能就不夠用了。實(shí)際上,只有很少的情況適合使用float類型,例如,需要快速地處理單精度數(shù)據(jù),或者需要存儲(chǔ)大量數(shù)據(jù)。

float類型的數(shù)值有一個(gè)后綴F(例如,3.402F)。沒(méi)有后綴F的浮點(diǎn)數(shù)值(如3.402)默認(rèn)為double類型。當(dāng)然,也可以在浮點(diǎn)數(shù)值后面添加后綴D(例如,3.402D)。

在JDK 5.0中,可以使用十六進(jìn)制表示浮點(diǎn)數(shù)值。例如,0.125可以表示成0x1.0p-3。在十六進(jìn)制表示法中,使用p表示指數(shù),而不是e。

所有的浮點(diǎn)數(shù)值計(jì)算都遵循IEEE 754規(guī)范。下面是三個(gè)特殊的浮點(diǎn)數(shù)值:

? 正無(wú)窮大

? 負(fù)無(wú)窮大

? NaN

上面這三個(gè)數(shù)值用于表示溢出和出錯(cuò)情況。例如,一個(gè)正整數(shù)除以0的結(jié)果為正無(wú)窮大。計(jì)算0/0或者負(fù)數(shù)的平方根結(jié)果為NaN。

char類型

要想弄清char類型,就必須了解Unicode編碼表。Unicode打破了傳統(tǒng)字符編碼方法的限制。在Unicode出現(xiàn)之前,已經(jīng)有許多種不同的標(biāo)準(zhǔn):美國(guó)的ASCII、西歐語(yǔ)言中的ISO 8859-1、俄國(guó)的KOI-8、中國(guó)的GB118030和BIG-5等等。這樣就產(chǎn)生了下面兩個(gè)問(wèn)題:一個(gè)是對(duì)于任意給定的代碼值,在不同的編碼方案下有可能對(duì)應(yīng)不同的字母;二是采用大字符集的語(yǔ)言其編碼長(zhǎng)度有可能不同。例如,有些常用的字符采用單字節(jié)編碼,而另一些字符則需要兩個(gè)或更多個(gè)字節(jié)。

設(shè)計(jì)Unicode編碼就是要解決這些問(wèn)題。在20世紀(jì)80年代開(kāi)始啟動(dòng)設(shè)計(jì)工作時(shí),人們認(rèn)為兩個(gè)字節(jié)的代碼寬度足以能夠?qū)⑹澜缟细鞣N語(yǔ)言的所有字符進(jìn)行編碼,并有足夠的空間留給未來(lái)的擴(kuò)展。在1991年發(fā)布了Unicode 1.0,當(dāng)時(shí)僅占用65 536個(gè)代碼值的一小部分。在設(shè)計(jì)Java時(shí)決定采用16位的Unicode字符集,這樣會(huì)比使用8位字符集的程序設(shè)計(jì)語(yǔ)言有很大的改進(jìn)。

十分遺憾,經(jīng)過(guò)一段時(shí)間,不可避免的事情發(fā)生了。Unicode字符超過(guò)了65 536個(gè),其主要原因是添加了大量的漢語(yǔ)、日語(yǔ)和韓國(guó)語(yǔ)言中的表意文字。現(xiàn)在,16位的char類型已經(jīng)不能滿足描述所有Unicode字符的需要了。

下面利用一些專用術(shù)語(yǔ)解釋一下Java語(yǔ)言解決這個(gè)問(wèn)題的基本方法。從JDK 5.0開(kāi)始。代碼點(diǎn)(code point)是指與一個(gè)編碼表中的某個(gè)字符對(duì)應(yīng)的代碼值。在Unicode標(biāo)準(zhǔn)中,代碼點(diǎn)采用十六進(jìn)制書(shū)寫(xiě),并加上前綴U+,例如U+0041就是字母A的代碼點(diǎn)。Unicode的代碼點(diǎn)可以分成17個(gè)代碼級(jí)別(code plane)。第一個(gè)代碼級(jí)別稱為基本的多語(yǔ)言級(jí)別(basic multilingual plane),代碼點(diǎn)從U+0000到U+FFFF,其中包括了經(jīng)典的Unicode代碼;其余的16個(gè)附加級(jí)別,代碼點(diǎn)從U+10000到U+10FFFF,其中包括了一些輔助字符(supplementary character)。

UTF-16編碼采用不同長(zhǎng)度的編碼表示所有Unicode代碼點(diǎn)。在基本的多語(yǔ)言級(jí)別中,每個(gè)字符用16位表示,通常被稱為代碼單元(code unit);而輔助字符采用一對(duì)連續(xù)的代碼單元進(jìn)行編碼。這樣構(gòu)成的編碼值一定落入基本的多語(yǔ)言級(jí)別中空閑的2048字節(jié)內(nèi),通常被稱為替代區(qū)域(surrogate area)(U+D800到U+DBFF用于第一個(gè)代碼單元,U+DC00到U+DFFF用于第二個(gè)代碼單元)。這種設(shè)計(jì)十分巧妙,我們可以從中迅速地知道一個(gè)代碼單元是一個(gè)字符的編碼,還是一個(gè)輔助字符的第一或第二部分。例如,對(duì)于整數(shù)集合的數(shù)學(xué)符號(hào) ,它的代碼點(diǎn)是U+1D56B,并且是用兩個(gè)代碼單元U+D835和U+DD6B編碼的。(有關(guān)編碼算法的描述請(qǐng)參閱http://en.wikipedia.org/wiki/UTF-16。)

在Java中,char類型用UTF-16編碼描述一個(gè)代碼單元。

我們強(qiáng)烈建議不要在程序中使用char類型,除非確實(shí)需要對(duì)UTF-16代碼單元進(jìn)行操作。最好將需要處理的字符串用抽象數(shù)據(jù)類型表示。(有關(guān)這方面的內(nèi)容將在稍后討論。)

前面已經(jīng)說(shuō)過(guò),在有些情況下,可能需要用到char的值。最常見(jiàn)的情況是字符常量。例如,'A'是一個(gè)編碼為65的字符常量,它與"A"完全不同,是一個(gè)包含字符A的字符串。Unicode代碼單元可以表示為十六進(jìn)制的值,其范圍從 到。例如,?是注冊(cè)符號(hào)(?);π是希臘字母π。

除了可以采用轉(zhuǎn)義序列符u表示Unicode代碼單元的編碼之外,還有一些用于表示特殊字符的轉(zhuǎn)義序列符,請(qǐng)參看表3-3。所有這些轉(zhuǎn)義序列符都可以出現(xiàn)在字符常量或字符串的引號(hào)內(nèi)。

例如,'?'或"Hello"。轉(zhuǎn)義序列符u還可以出現(xiàn)在字符常量或字符串的引號(hào)之外(而其他所有轉(zhuǎn)義序列不可以)。例如:

public static void main (String[] args)

這種形式完全符合語(yǔ)法規(guī)則,[和 ] 是 [ 和 ] 的Unicode代碼點(diǎn)的UTF-16編碼。

boolean類型

boolean(布爾)類型有兩個(gè)值:false和true,用來(lái)判定邏輯條件。這兩個(gè)值不能與整型進(jìn)行相互轉(zhuǎn)換。

變量

在Java中,每一個(gè)變量屬于一種類型(type)。在聲明變量時(shí),變量所屬的類型位于前面,隨后是變量名。這里列舉一些聲明變量的例子:

double salary;

int vacationDays;

long earthPopulation;

boolean done;

注意,用于Java中,聲明是一條完整的語(yǔ)句,因此每一個(gè)聲明都必須以分號(hào)結(jié)束。

變量名必須是一個(gè)以字母開(kāi)頭的字母或數(shù)字序列。需要注意,與大多數(shù)程序設(shè)計(jì)語(yǔ)言相比,Java中“字母”和“數(shù)字”的范圍要大。字母包括'A'~'Z'、'a'~'z'、'_'和在某種語(yǔ)言中代表字母的任何Unicode字符。例如,德國(guó)的用戶可以在變量名中使用字母'?';希臘人可以使用π。同樣,數(shù)字包括'0'~'9'和在某種語(yǔ)言中代表數(shù)字的任何Unicode字符。但'+'和'?'這樣的符號(hào)不能出現(xiàn)在變量名中,空格也不行。變量名中所有的字符都是有意義的,并且大小寫(xiě)敏感。對(duì)變量名的長(zhǎng)度沒(méi)有限制。

另外,不能將變量名命名為Java保留字。(請(qǐng)參看附錄A中的Java保留字列表。)

可以在一行中聲明多個(gè)變量:

int i, j; //both are integers

不過(guò),不提倡使用這種風(fēng)格。逐一聲明每一個(gè)變量可以提高程序的可讀性。

初始化變量

聲明一個(gè)變量之后,必須利用賦值語(yǔ)句對(duì)變量進(jìn)行顯式初始化,千萬(wàn)不要使用一個(gè)未被初始化的變量。例如,Java編譯器認(rèn)為下面語(yǔ)句序列是錯(cuò)誤的:

int vacationDays;

System.out.println(vacationDays); //ERROR-variable not initialized

要想對(duì)一個(gè)已經(jīng)聲明過(guò)的變量進(jìn)行賦值,就需要將變量名放在等號(hào)(=)左側(cè),具有相應(yīng)取值的Java表達(dá)式放在等號(hào)的右側(cè)。

int vacationDays;

vacationDays = 12;

也可以將變量的聲明和初始化放在同一行中。例如:

int vacationDays = 12;

最后,在Java中可以將聲明放在代碼中的任何地方。例如,在Java中,下列代碼的書(shū)寫(xiě)形式是完全合法的:

double salary = 65000.0;

System.out.println(salary);

int vacationDays = 12; // ok to declare a variable here

在Java中,變量的聲明盡可能地靠近變量第一次使用的地方,這是一種良好的程序編寫(xiě)風(fēng)格。

extern int i;

是聲明一個(gè)變量。在Java中,不區(qū)分變量的聲明與定義。

常量

在Java中,利用關(guān)鍵字final聲明常量。例如:

關(guān)鍵字final表示這個(gè)變量只能被賦值一次。一旦被賦值之后,就不能夠再更改了。習(xí)慣上,常量名使用大寫(xiě)。

在Java中,經(jīng)常希望某個(gè)常量可以在一個(gè)類中的多個(gè)方法中使用,通常將這些常量稱為類常量。可以使用關(guān)鍵字static final設(shè)置一個(gè)類常量。下面是使用類常量的例子:

需要注意,類常量的定義位于main方法的外部。因此,在同一個(gè)類的其他方法中也可以使用這個(gè)常量。而且,如果一個(gè)常量被聲明為public,那么其他類的方法也可以使用這個(gè)常量。在這個(gè)例子中,Constants2.CM_PER-INCH就是這樣一個(gè)常量。

運(yùn)算符

在Java中,使用算術(shù)運(yùn)算符+、-、*、/ 表示加、減、乘、除運(yùn)算。當(dāng)參與 / 運(yùn)算的兩個(gè)操作數(shù)都是整數(shù)時(shí),表示整數(shù)除法;否則,表示浮點(diǎn)除法。整數(shù)的求余操作(有時(shí)稱為取模)用%表示。例如,15/2等于7,15%2等于1,15.0/2等于7.5。

需要注意,整數(shù)被0除將會(huì)產(chǎn)生一個(gè)異常,而浮點(diǎn)數(shù)被0除將會(huì)得到無(wú)窮大或NaN。

可以在賦值語(yǔ)句中采用簡(jiǎn)化的格式書(shū)寫(xiě)二元算術(shù)運(yùn)算符。

例如,

x += 4;

等價(jià)于

x = x + 4;

(通常,將運(yùn)算符放在賦值號(hào)的左側(cè),如*= 或 %=。)

自增運(yùn)算符與自減運(yùn)算符

當(dāng)然,程序員都知道加1、減1是數(shù)值變量最常見(jiàn)的操作。在Java中,借鑒了C和C++的實(shí)現(xiàn)方式,也使用了自增、自減運(yùn)算符:n++將變量n的當(dāng)前值加1;n--將n的值減1。例如:

int n =12;

n++;

n的值將變?yōu)?3。因?yàn)檫@些運(yùn)算符改變了變量的值,所以它的操作數(shù)不能是數(shù)值。例如,4++就是一條非法的語(yǔ)句。

實(shí)際上,這兩個(gè)運(yùn)算符有兩種形式。上面介紹的是運(yùn)算符放在后面的“后綴”形式,還有一種“前綴”形式(++n)都是對(duì)變量值加1。但在表達(dá)式中,這兩種形式就有區(qū)別了。前綴方式先進(jìn)行加1運(yùn)算;后綴方式則使用變量原來(lái)的值。

int m = 7;

int n = 7;

int a = 2 * ++m;//now a is 16, m is 8

int b = 2 * n++;//now b is 14, n is 8

我們建議不要在其他表達(dá)式的內(nèi)部使用++,這樣編寫(xiě)的代碼很容易令人感到迷惑,并會(huì)產(chǎn)生煩人的bug。

顯然,++ 運(yùn)算符構(gòu)成了C++語(yǔ)言名稱,這也引發(fā)了有關(guān)程序設(shè)計(jì)語(yǔ)言的第一個(gè)笑話。C++的反對(duì)者認(rèn)為這種語(yǔ)言的名稱也存在著bug,他們說(shuō):“因?yàn)橹挥袑?duì)它改進(jìn)之后,我們才有可能使用它,所以它的名字應(yīng)該命名為++C。”

關(guān)系運(yùn)算符與boolean運(yùn)算符

Java具有各種關(guān)系運(yùn)算符。其中,使用兩個(gè)等號(hào) = = 檢測(cè)是否相等。例如,3 = = 7的值為false。

使用 != 檢測(cè)是否不相等。例如,3 != 7的值為true。

另外,經(jīng)常使用的運(yùn)算符還有 (大于)、<=(小于等于)和>=(大于等于)。

Java沿用了C++的習(xí)慣,用&&表示邏輯“與”、用 || 表示邏輯“或”。從!= 運(yùn)算符很容易看出,!表示邏輯“非”。&&和 || 是按照“短路”方式求值的。如果第一個(gè)操作數(shù)已經(jīng)能夠確定值,第二個(gè)操作數(shù)就不必計(jì)算了。如果用 && 對(duì)兩個(gè)表達(dá)式(expression)進(jìn)行計(jì)算:

expression1 && expression2

并且第一個(gè)表達(dá)式值為false,那么結(jié)果不可能為真。因此,第二個(gè)表達(dá)式就沒(méi)有必要計(jì)算了。這種方式可以避免一些錯(cuò)誤的發(fā)生。例如,表達(dá)式:

x != 0 && 1 / x > x + y // no division by 0

當(dāng)x為0時(shí),不計(jì)算第二部分,因此1 / x不被計(jì)算也不會(huì)出現(xiàn)除以0的錯(cuò)誤。

與之類似,對(duì)于expression1 || expression2 ,當(dāng)?shù)谝粋€(gè)表達(dá)式為true時(shí),結(jié)果自動(dòng)為true,不必再計(jì)算第二部分。

最后,Java支持三元操作?:,在很多時(shí)候,這個(gè)操作非常有用。表達(dá)式

condition ? expression1 : expression2

當(dāng)條件為真時(shí)計(jì)算第1個(gè)表達(dá)式,否則計(jì)算第2個(gè)表達(dá)式。

例如:

x < y ? x : y

返回x和y中較小的那個(gè)值。

位運(yùn)算符

在處理整型數(shù)值時(shí),可以直接對(duì)組成整型數(shù)值的各個(gè)位進(jìn)行操作。這意味著可以使用屏蔽技術(shù)獲得整數(shù)中的各個(gè)位。位運(yùn)算符包括:

&(“與”)、|(“或”)、^(“異或”)、~(“非”)

這些運(yùn)算符在位模式下工作。例如,如果n是一個(gè)整型變量,并且用二進(jìn)制表示的n從右數(shù)第4位為1,那么

int fourthBitFromRight = (n & 8) / 8;

返回1;否則返回0。通過(guò)使用2的冪次方和&運(yùn)算可以將其他位屏蔽掉,而只保留其中的某一位。

數(shù)學(xué)函數(shù)與常量

在Math類中,包含了各種各樣的數(shù)學(xué)函數(shù)。在編寫(xiě)不同類別的程序時(shí),可能需要的函數(shù)也不同。

要想計(jì)算一個(gè)數(shù)值的平方根,可以使用sqrt方法:

double x = 4;double y = Math.sqrt(x);System.out.println(y); //prints 2.0

在Java中,沒(méi)有冪運(yùn)算。因此求冪需要借助于Math類的pow方法。語(yǔ)句:

double y = Math.pow(x, a) ;

將y的值設(shè)置為x的a次方(xa)。pow方法有兩個(gè)double類型的參數(shù),其返回結(jié)果也為double類型。

Math類提供了一些常用的三角函數(shù):

Math.sin

Math.cos

Math.tan

Math.atan

Math.atan2

還有指數(shù)函數(shù)以及它的反函數(shù)—自然對(duì)數(shù):

Math.exp

Math.log

最后,Java還提供了兩個(gè)用于表示π和e常量的近似值:

Math.PI

Math.E

數(shù)值類型之間的轉(zhuǎn)換

在程序運(yùn)行時(shí),經(jīng)常需要將一種數(shù)值類型轉(zhuǎn)換為另一種數(shù)值類型。圖3-1給出了數(shù)值類型之間的合法轉(zhuǎn)換。

圖3-1 數(shù)值類型之間的合法轉(zhuǎn)換

在圖3-1中有6個(gè)實(shí)箭頭,表示無(wú)數(shù)據(jù)丟失的轉(zhuǎn)換;有3個(gè)虛箭頭,表示可能有精度損失的轉(zhuǎn)換。例如,123 456 789是一個(gè)大整數(shù),它所包含的位數(shù)比f(wàn)loat類型所能夠表達(dá)的位數(shù)多。當(dāng)將這個(gè)整型數(shù)值轉(zhuǎn)換為float類型時(shí),將會(huì)得到同樣大小的結(jié)果,但卻失去了一定的精度。

int n = 123456789;

float f = n; // f is 1.23456792E8

當(dāng)使用上面兩個(gè)數(shù)值進(jìn)行二元操作時(shí)(例如n + f,n是整數(shù),f是浮點(diǎn)數(shù)),先要將兩個(gè)操作數(shù)轉(zhuǎn)換為同一種類型,然后再進(jìn)行計(jì)算。

? 如果兩個(gè)操作數(shù)中有一個(gè)是double類型的,那么另一個(gè)操作數(shù)將會(huì)轉(zhuǎn)換為double類型。

? 否則,如果其中一個(gè)操作數(shù)是float類型,那么另一個(gè)操作數(shù)將會(huì)轉(zhuǎn)換為float類型。

? 否則,如果其中一個(gè)操作數(shù)是long類型,那么另一個(gè)操作數(shù)將會(huì)轉(zhuǎn)換為long類型。

? 否則,兩個(gè)操作數(shù)都將被轉(zhuǎn)換為int類型。

強(qiáng)制類型轉(zhuǎn)換

在上一小節(jié)中看到,在必要的時(shí)候,int類型的值將會(huì)自動(dòng)地轉(zhuǎn)換為double類型。但另一方面,有時(shí)也需要將double轉(zhuǎn)換成int。在Java中,允許進(jìn)行這種數(shù)值之間的類型轉(zhuǎn)換,當(dāng)然,有可能會(huì)丟失一些信息。在這種情況下,需要通過(guò)強(qiáng)制類型轉(zhuǎn)換(cast)實(shí)現(xiàn)這個(gè)操作。

強(qiáng)制類型轉(zhuǎn)換的語(yǔ)法格式是在圓括號(hào)中給出想要轉(zhuǎn)換的目標(biāo)類型,隨后緊跟待轉(zhuǎn)換的變量名。

例如:

double x = 9.997;

int nx = (int)x;

這樣,變量nx的值為9。強(qiáng)制類型轉(zhuǎn)換將通過(guò)截?cái)嘈?shù)部分來(lái)把一個(gè)浮點(diǎn)值轉(zhuǎn)換為整型。

如果想對(duì)浮點(diǎn)數(shù)進(jìn)行舍入運(yùn)算,得到最接近的整數(shù)(在很多情況下,希望使用這種操作方式),就需要使用Math.round方法:

double x = 9.997;

int nx = (int) Math.round (x);

現(xiàn)在,變量nx的值為10。當(dāng)調(diào)用round的時(shí)候,仍然需要使用強(qiáng)制類型轉(zhuǎn)換(int)。其原因是round方法返回的結(jié)果為long類型,由于存在信息丟失的可能性,所以只有使用顯示的強(qiáng)制類型轉(zhuǎn)換才能夠?qū)ong類型轉(zhuǎn)換成int類型。

括號(hào)與運(yùn)算符級(jí)別

表3-4給出了運(yùn)算符的優(yōu)先級(jí)。如果不使用圓括號(hào),就按照給出的運(yùn)算符優(yōu)先級(jí)次序進(jìn)行計(jì)算。同一個(gè)級(jí)別的運(yùn)算符按照從左到右的次序進(jìn)行計(jì)算(除了表中給出的右結(jié)合運(yùn)算符之外。)

例如,由于 && 的優(yōu)先級(jí)比 || 的優(yōu)先級(jí)高,所以表達(dá)式

a && b || c

等價(jià)于

( a && b ) || c

又因?yàn)?+= 是右結(jié)合運(yùn)算符,所以表達(dá)式

a += b += c

等價(jià)于

a += ( b += c )

也就是將b += c 的結(jié)果(加上c之后的b)加到a上。

枚舉類型

有些時(shí)候,變量的取值僅在一個(gè)有限的集合內(nèi)。例如:銷售的服裝或比薩餅只有小、中、大和超大這四種尺寸。當(dāng)然,可以將這些尺寸編碼為1、2、3、4或S、M、L、X。但這樣做存在著一定的隱患。在變量中很可能保存的是一個(gè)錯(cuò)誤的值(如0或m)。

從JDK 5.0開(kāi)始,針對(duì)這種情況,可以自定義枚舉類型。枚舉類型包括有限個(gè)命名的值。例如,enum Size {SMALL, MEDIUM, LARGE, EXTRA_LARGE };

現(xiàn)在,可以聲明這樣一種類型的變量:

Size s = Size.MEDIUM;

Size類型的變量只能存儲(chǔ)該類型聲明中給定的某個(gè)枚舉值,或者null值。

有關(guān)枚舉類型的詳細(xì)內(nèi)容將在第5章介紹。

字符串

從概念上講,Java字符串就是Unicode字符序列。例如,串“Java?”由5個(gè)Unicode字符J、a、v、a和?組成。Java 沒(méi)有內(nèi)置的字符串類型,而是在標(biāo)準(zhǔn)Java類庫(kù)中提供了一個(gè)預(yù)定義類String。每個(gè)用雙引號(hào)括起來(lái)的字符串都是String類的一個(gè)實(shí)例:

String e = ""; //an empty string

String greeting = "Hello";

3.6.1 代碼點(diǎn)與代碼單元

Java字符串由char值序列組成。從前面已經(jīng)看到,char數(shù)據(jù)類型是一個(gè)采用UTF-16編碼表示Unicode代碼點(diǎn)的代碼單元。大多數(shù)的常用Unicode字符使用一個(gè)代碼單元就可以表示,而輔助字符需要一對(duì)代碼單元表示。

length方法將返回采用UTF-16編碼表示的給定字符串所需要的代碼單元數(shù)量。例如:

String greeting = "Hello";

int n = greeting.length( ); // is 5.

要想得到實(shí)際的長(zhǎng)度,即代碼點(diǎn)數(shù)量,可以調(diào)用:

int cpCount = greeting.codePointCount(0,greeting.length( ));

調(diào)用s.charAt(n) 將返回位置n的代碼單元,n介于0 ~ s.length( )-1之間。例如:

char first = greeting.charAt(0); //first is 'H'

char last = greeting.charAt(4); //last is 'o'

要想得到第i個(gè)代碼點(diǎn),應(yīng)該使用下列語(yǔ)句

int index = greeting.offsetByCodePoints(0,i);

int cp = greeting.codePointAt(index);

為什么我們對(duì)代碼單元大驚小怪?請(qǐng)考慮下列語(yǔ)句:

is the set of integers

使用UTF-16編碼表示 需要兩個(gè)代碼單元。調(diào)用

char ch = sentence.charAt(1)

返回的不是空格,而是 的第二個(gè)代碼單元。為了避免這種情況的發(fā)生,請(qǐng)不要使用char類型。這太低級(jí)了。

如果想要遍歷一個(gè)字符串,并且依次查看每一個(gè)代碼點(diǎn),可以使用下列語(yǔ)句:

int cp = sentence.codePointAt(i);

if (Character.isSupplementaryCodePoint(cp)) i += 2;

else i++;

非常幸運(yùn),codePointAt方法能夠辨別一個(gè)代碼單元是輔助字符的第一部分還是第二部分,并能夠返回正確的結(jié)果。也就是說(shuō),可以使用下列語(yǔ)句實(shí)現(xiàn)回退操作:

i--;

int cp = sentence.codePointAt(i);

if (Character.isSupplementaryCodePoint(cp)) i--;

子串

String類的substring方法可以從一個(gè)較大的字符串提取出一個(gè)子串。例如:

String greeting = "Hello";

String s = greeting.substring(0, 3);

創(chuàng)建了一個(gè)由字符“Hel”組成的字符串。

substring的第二個(gè)參數(shù)是不希望復(fù)制的第一個(gè)代碼單元。這里復(fù)制的代碼單元位置為0、1、2(從0到2,包括0和2)。在substring中的計(jì)數(shù)是從0~3。

substring的工作方式有一個(gè)優(yōu)點(diǎn):容易計(jì)算子串中代碼單元的數(shù)量。字符串s.substring(a, b) 將包含b-a個(gè)代碼單元。例如,子串“Hel”的代碼單元數(shù)量為3-0=3。

字符串編輯

String類沒(méi)有提供用于修改現(xiàn)存字符串的方法。如果希望將greeting的內(nèi)容修改為“Help!”,不能直接地將greeting的最后兩個(gè)位置的字符修改為'p'和'!'。這對(duì)于一個(gè)C 程序員來(lái)說(shuō)會(huì)感到無(wú)從下手。如何修改這個(gè)字符串呢?在Java中實(shí)現(xiàn)這項(xiàng)操作相當(dāng)容易,首先提取需要的子串,然后再拼接上需要替換的字符串。

greeting = greeting.substring(0,3) + "p!";

上面這條語(yǔ)句將greeting當(dāng)前值修改為“Help!”。

由于不能修改Java字符串中的字符,所以在Java文檔中將String類對(duì)象稱為不可變字符串,如同數(shù)字3永遠(yuǎn)是數(shù)字3一樣,字符串“Hello”永遠(yuǎn)包含H、e、l、l和o的代碼單元序列,而不能修改其中的任何一個(gè)字符。當(dāng)然,可以修改字符串變量greeting的內(nèi)容,讓它引用一個(gè)不同的字符串,如同可以將一個(gè)存放3的數(shù)值變量改成存放4一樣。

這樣做是否會(huì)降低運(yùn)行效率呢?看起來(lái)好象修改一個(gè)代碼單元要比創(chuàng)建一個(gè)新字符串更加簡(jiǎn)潔。答案是:也對(duì),也不對(duì)。的確,通過(guò)拼接“Hel”和“p!”來(lái)創(chuàng)建一個(gè)新字符串的效率確實(shí)不高。但是,不可變字符串卻有一個(gè)優(yōu)點(diǎn):編譯器可以將字符串共享。

要想了解具體的工作方式,可以想象將各種字符串存放在公共的存儲(chǔ)池中。字符串變量指向存儲(chǔ)池中相應(yīng)的位置。如果復(fù)制一個(gè)字符串變量,那么原始字符串與復(fù)制的字符串共享相同的字符。總而言之,Java的設(shè)計(jì)者認(rèn)為共享帶來(lái)的高效率遠(yuǎn)遠(yuǎn)勝過(guò)于提取子串,然后再拼接字符串所帶來(lái)的低效率。

查看一下程序會(huì)發(fā)現(xiàn):不會(huì)經(jīng)常修改字符串,而是對(duì)字符串進(jìn)行比較。當(dāng)然,在有些情況下,直接對(duì)字符串進(jìn)行操作會(huì)更加有效。(例如,將源自文件或鍵盤(pán)的單個(gè)字符匯集成字符串。)

為此Java提供了一個(gè)獨(dú)立的StringBuilder類,在第12章中將詳細(xì)地闡述它。如果不太注重字符串的處理效率,就可以不理會(huì)StringBuilder,而只使用String。

拼接

與絕大多數(shù)的程序設(shè)計(jì)語(yǔ)言一樣,Java語(yǔ)言允許使用 + 號(hào)連接(拼接)兩個(gè)字符串。

String expletive = "Expletive";

String PG13 = "deleted";

String message = expletive + PG13;

上面的代碼將“Expletivedeleted”賦給變量message。(注意,單詞之間沒(méi)有空格,+號(hào)按照給定的次序?qū)蓚€(gè)字符串拼接起來(lái)。)

當(dāng)將一個(gè)字符串與一個(gè)非字符串的值進(jìn)行拼接時(shí),后者被轉(zhuǎn)換成字符串。(在第5章中可以看到,任何一個(gè)Java對(duì)象都可以轉(zhuǎn)換成字符串。)例如:

int age = 13;

String rating = "PG" + age;

rating得到“PG13”。

這種特性通常用在輸出語(yǔ)句中。例如,

System.out.println ("The answer is" + answer);

這是一條合法的語(yǔ)句,并且將會(huì)打印出所希望的結(jié)果(單詞is后面加了一個(gè)空格,輸出時(shí)也會(huì)加上這個(gè)空格。)

檢測(cè)字符串是否相等

可以使用equals方法檢測(cè)兩個(gè)字符串是否相等。如果字符串s與字符串t相等,則表達(dá)式s.equals(t)返回true;否則,返回false。需要注意,s與t可以是字符串變量,也可以是字符串常量。

例如,表達(dá)式

"Hello".equals(greeting)

是合法的。要想檢測(cè)兩個(gè)字符串是否相等,而不區(qū)分大小寫(xiě),可以使用equalsIgnoreCase方法。

"Hello".equalsIgnoreCase("hello")

一定不能使用 = = 運(yùn)算符檢測(cè)兩個(gè)字符串是否相等!這個(gè)運(yùn)算符只能夠確定兩個(gè)字符串是否被放置在同一個(gè)位置。當(dāng)然,如果字符串放置在同一個(gè)位置,它們必然相等。但是,完全有可能將內(nèi)容相同的兩個(gè)字符串放置在不同的位置上。

String greeting = "Hello"; //initialize greeting to a string

if (greeting = = "Hello") ...

// probably true

if (greeting.substring(0, 3) = = "Hel")...

//probably false

如果虛擬機(jī)總是將相同的字符串共享,就可以使用 == 運(yùn)算符檢測(cè)是否相等。但實(shí)際上只有字符串常量是共享的,而+或substring等操作產(chǎn)生的結(jié)果都不是共享的。因此,永遠(yuǎn)不要使用 ==運(yùn)算符測(cè)試字符串的相等性,否則在程序中會(huì)出現(xiàn)很糟糕的bug,從表面上看很像隨機(jī)產(chǎn)生的間歇性錯(cuò)誤。

Java中的String類包含了50多個(gè)方法。令人驚訝的是絕大多數(shù)都很有用,可以想象使用的機(jī)會(huì)有多么頻繁。下面的API注釋匯總了最常用的部分方法。

java.lang.string 1.0

? char charAt (int index)

返回指定位置的代碼單元。除非對(duì)底層的代碼單元感興趣,否則不需要調(diào)用這個(gè)方法。

? int codePointAt(int index) 5.0

返回從給定位置開(kāi)始或結(jié)束的代碼點(diǎn)。

? int offsetByCodePoints(int startIndex, int cpCount) 5.0

返回從startIndex代碼點(diǎn)開(kāi)始,位移cpCount后的代碼點(diǎn)索引。

? int compareTo(String other)

按照字典順序,如果字符串位于other之前,則返回一個(gè)負(fù)數(shù);如果字符串位于other之后,則返回一個(gè)正數(shù);如果兩個(gè)字符串相等,則返回0。

? boolean endsWith(String suffix)

如果字符串以suffix結(jié)尾,則返回true。

? boolean equals(Object other)

如果字符串與other相等,則返回true。

? boolean equalsIgnoreCase(String other)

如果字符串與other相等(忽略大小寫(xiě)),則返回true。

? int index0f(String str)

? int index0f(String str, int fromIndex)

? int index0f(int cp)

? int index0f(int cp, int fromIndex)

返回與字符串str或代碼點(diǎn)cp匹配的的第一個(gè)子串的開(kāi)始位置,該位置從索引0或fromIndex開(kāi)始計(jì)算。如果在原始串中不存在str,則返回-1。

? int lastIndex0f(String str)

? int lastIndex0f(String str, int fromIndex)

? int lastindex0f(int cp)

? int lastindex0f(int cp, int fromIndex)

返回與字符串str或代碼點(diǎn)cp匹配的最后一個(gè)子串的開(kāi)始位置,該位置從原始串尾端或

fromIndex開(kāi)始計(jì)算。

? int length( )

返回字符串的長(zhǎng)度。

? int codePointCount(int startIndex, int endIndex) 5.0

返回startIndex和endIndex-1之間的代碼點(diǎn)數(shù)量。沒(méi)有配成對(duì)的替代字符作為代碼點(diǎn)計(jì)數(shù)。

? String replace(CharSequence oldString,CharSequence newString)

返回一個(gè)新字符串,該字符串用newString代替原始字符串中所有的oldString。可以用String或

StringBuilder對(duì)象作為CharSequence參數(shù)。

? boolean startsWith(String prefix)

如果字符串以preffix字符串開(kāi)始,則返回true。

? String substring(int beginIndex)

? String substring(int beginIndex, int endIndex)

返回一個(gè)新字符串,該串包含從原始字符串beginIndex到串尾或endIndex-1的所有代碼單元。

? String toLowerCase( )

返回一個(gè)新字符串,該串將原始字符串中的所有大寫(xiě)字母改成了小寫(xiě)字母。

? String toUpperCase( )

返回一個(gè)新字符串,該串將原始字符串中的所有小寫(xiě)字母改成了大寫(xiě)字母。

? String trim( )

返回一個(gè)新字符串,該串刪除了原始字符串頭部和尾部的空格。

閱讀聯(lián)機(jī)API文檔

正如前面所看到的,String類包含許多方法。而且,在標(biāo)準(zhǔn)庫(kù)中有幾千個(gè)類,方法數(shù)量則更加驚人。要想記住所有的類和方法是一件不太不可能的事情。因此,了解在線API文檔十分重要,從中可以查閱到標(biāo)準(zhǔn)類庫(kù)中的所有類和方法。API文檔是JDK的一部分,它是HTML格式的。讓瀏覽器指向安裝JDK的docs/api/index.html子目錄,就可以看到如圖3-2所示的屏幕。

可以看到,屏幕被分成三個(gè)窗框。在左上方的小窗框中顯示了可使用的所有包。在它下面稍大的窗框中列出了所有的類。點(diǎn)擊任何一個(gè)類名之后,該類的API文檔就會(huì)顯示在右側(cè)的大窗框中(請(qǐng)參看圖3-3)。例如,要獲得有關(guān)String類方法的更多信息,可以滾動(dòng)第二個(gè)窗框,直到看見(jiàn)String鏈接為止,然后點(diǎn)擊這個(gè)鏈接。

然后,滾動(dòng)右面的窗框,直到看見(jiàn)按字母順序排列的所有方法為止(請(qǐng)參看圖3-4)。點(diǎn)擊任何一個(gè)方法名便可以查看這個(gè)方法的詳細(xì)描述(參見(jiàn)圖3-5)。例如,如果點(diǎn)擊compare-ToIgnoreCase鏈接,就會(huì)看到compareToIgnoreCase方法的描述。

輸入輸出

為了增加后面例子程序的趣味性,需要程序能夠接收輸入,并以適當(dāng)?shù)母袷捷敵觥.?dāng)然,現(xiàn)代的程序都使用GUI收集用戶的輸入,編寫(xiě)這種界面的程序需要使用較多的工具與技術(shù),目前還不具備這些條件。主要原因是需要熟悉Java程序設(shè)計(jì)語(yǔ)言,因此只要有簡(jiǎn)單的用于輸入輸出的控制臺(tái)就可以了。第7章~第9章將詳細(xì)地介紹GUI程序設(shè)計(jì)。

讀取輸入

前面已經(jīng)看到,打印輸出到“標(biāo)準(zhǔn)輸出流”(即控制臺(tái)窗口)是一件非常容易的事情,只要調(diào)用System.out.println即可。而在JDK 5.0之前卻沒(méi)有從控制臺(tái)窗口讀取輸入的簡(jiǎn)便方法。值得慶賀的是,這一狀況終于得到了改變。

要想通過(guò)控制臺(tái)進(jìn)行輸入,首先需要構(gòu)造一個(gè)Scanner對(duì)象,它附屬于“標(biāo)準(zhǔn)輸入流”System.in。

Scanner in = new Scanner(System.in);

現(xiàn)在,就可以使用Scanner類的各種方法實(shí)現(xiàn)輸入操作了。例如,nextLine方法將輸入一行。

System.out.print("What is your name?");

String name = in.nextLine( );

在這里,使用nextLine方法的主要原因是在輸入行中可能包含空格。如果讀取的是一個(gè)單詞(以空白符作為分隔符),則可以調(diào)用

String firstName = in.next( );

要想讀取一個(gè)整數(shù),可以使用nextInt方法。

System.out.print("How old are you?");

int age = in.nextInt( );

與此類似,要想讀取下一個(gè)浮點(diǎn)數(shù),可以使用nextDouble方法。

在例3-2的程序中,詢問(wèn)用戶姓名和年齡,然后打印一條如下格式的消息:

Hello, Cay. Next year, you’ll be 46

最后,在程序的最開(kāi)始添加上一行:

import java.util.* ;

Scanner類定義在java.util包中。當(dāng)使用的類不是定義在基本java.lang包中時(shí),一定要使用import指示字將相應(yīng)的包加載進(jìn)來(lái)。有關(guān)包與import指示字的詳細(xì)描述請(qǐng)參看第4章。

例3-2 InputTest.java

String input = JOptionPane.showInputDialog(promptString)它的返回值是用戶輸入的字符串。

例如,可以這樣詢問(wèn)用戶的名字:

String name = JOptionPane.showInputDialog("What is your name?");

如果想要輸入數(shù)值,還需要附加一步操作。

JOptionPane.showInputDialog方法返回一個(gè)字符串,而不是一個(gè)數(shù)值。不過(guò)可以使用Integer.parseInt或Double.parseDouble方法將字符串轉(zhuǎn)換成數(shù)值。例如,String input = JOptionPane.showInputDialog("How old are you?");

int age = Integer.parseInt(input);

如果用戶鍵入了45,字符串變量input將得到字符串“45”,然后調(diào)用Integer.parseInt方法將這個(gè)字符轉(zhuǎn)換為數(shù)值45。

JOptionPane類定義在javax.swing包中,因此,需要添加語(yǔ)句:

import javax.swing.*;

最后,需要說(shuō)明一點(diǎn),當(dāng)程序調(diào)用JOptionPane.showInputDialog時(shí),需要通過(guò)調(diào)用System.exit(0)結(jié)束應(yīng)用程序。這主要是技術(shù)上的原因。當(dāng)顯示一個(gè)對(duì)話框時(shí),就啟動(dòng)了一個(gè)新的控制線程。在main方法退出后,新線程并沒(méi)有自動(dòng)地終止。要想終止所有的線程,需要調(diào)用System.exit方法。(關(guān)于線程的詳細(xì)論述請(qǐng)參見(jiàn)本書(shū)卷II第1章。)下面這段程序應(yīng)用于JDK 5.0之前的版本,它的功能與例3-2一樣。

java.util.Scanner 5.0

? Scanner (InputStream in)

用指定的輸入流創(chuàng)建一個(gè)Scanner對(duì)象。

? String nextLine( )

讀取輸入的下一行內(nèi)容。

? String next( )

讀取輸入的下一個(gè)單詞(以空格作為分隔符)。

? int nextInt( )

? double nextDouble( )

讀取并轉(zhuǎn)換下一個(gè)表示整數(shù)或浮點(diǎn)數(shù)的字符序列。

? boolean hasNext( )

檢測(cè)輸入中是否還有單詞。

? boolean hasNextInt( )

? boolean hasNextDouble( )

檢測(cè)是否還有表示整數(shù)或浮點(diǎn)數(shù)的下一個(gè)字符序列。

javax.swing.JOptionPane 1.2

? static String showInputDialog(Object message)

顯示一個(gè)對(duì)話框,帶有信息提示、一個(gè)輸入框和“OK”、“Cancel”按鈕。這個(gè)方法將返回用戶輸入的字符串。

java.lang.System 1.0

? static void exit(int status)

終止虛擬機(jī)并將狀態(tài)碼傳遞給操作系統(tǒng)。習(xí)慣上,非0的狀態(tài)碼表示出錯(cuò)。

格式化輸出

可以使用System.out.print(x) 將數(shù)值x輸出到控制臺(tái)上。這條命令將以x對(duì)應(yīng)的數(shù)據(jù)類型所允許的最大非0數(shù)字位數(shù)打印輸出x。例如:

double x = 10000.0 / 3.0;

System.out.print(x);

打印

3333.3333333333335

如果希望顯示美元、美分等符號(hào),有可能會(huì)出現(xiàn)問(wèn)題。

在JDK 5.0之前,格式化數(shù)值曾引起過(guò)一些爭(zhēng)議。現(xiàn)在,JDK 5.0沿用了C語(yǔ)言庫(kù)函數(shù)中的printf方法。例如,調(diào)用

System.out.printf("%8.2f", x);

可以用8個(gè)字符的寬度和小數(shù)點(diǎn)后兩位的精度打印x。也就是說(shuō),打印輸出一個(gè)空格和7個(gè)字符,如下所示:

3333.33

在printf中,可以使用多個(gè)參數(shù),例如:

System.out.printf("Hello, %s. Next year, you’ll be %d", name, age);

每一個(gè)以%字符開(kāi)始的格式說(shuō)明符都用相應(yīng)的參數(shù)替換。格式說(shuō)明符結(jié)尾的轉(zhuǎn)換符將指示被格式化的數(shù)值類型:f表示浮點(diǎn)數(shù),s表示串,d表示十進(jìn)制整數(shù)。表3-5給出了所有轉(zhuǎn)換符。

另外,還可以給出控制格式化輸出的各種標(biāo)志。表3-6給出了所有的標(biāo)志。例如,逗號(hào)標(biāo)志添加了分組的分隔符。即

System.out.printf("%, .2f", 10000.0 / 3.0);

打印

3,333.33

可以使用多個(gè)標(biāo)志,例如,“%, ( .2f”,使用分組的分隔符并將負(fù)數(shù)括在括號(hào)內(nèi)。

可以使用靜態(tài)的String.format方法創(chuàng)建一個(gè)格式化的字符串,而不打印輸出:

String message = String.format("Hello, %s. Next year, you’ll be %d", name, age);

盡管在第4章之前,并沒(méi)有對(duì)Date類型進(jìn)行詳細(xì)描述,但基于完整性的考慮,這里簡(jiǎn)略地討論一下printf方法的日期與時(shí)間的格式化選項(xiàng)。可以使用兩個(gè)字符的格式,以t開(kāi)始,以表3-7中任意字母結(jié)束。例如,

System.out.printf("%tc", new Date( ));

這條語(yǔ)句將用下面的格式打印當(dāng)前的日期和時(shí)間:

Mon Feb 09 18:05:19 PST 2004

從表3-7可以看到,某些格式只給出了給定日期的一部分信息。例如,只有日期或只有月份。

如果需要多次對(duì)日期操作才能實(shí)現(xiàn)對(duì)每一部分格式化的目的就太笨拙了。為此,可以采用一個(gè)格式化的字符串指出要被格式化的參數(shù)索引。索引必須緊跟在%后面,并以$終止。例如,System.out.printf("%1$s %2$tB %2$te, %2$tY", "Due date:", new Date( ));

打印

Due date: February 9, 2004

作為替代方案,還可以使用 < 標(biāo)志。它指出前面格式說(shuō)明中的參數(shù)要再次使用。也就是說(shuō),下列語(yǔ)句將產(chǎn)生與前面語(yǔ)句同樣的輸出結(jié)果。

System.out.printf("%s %tB %

現(xiàn)在,已經(jīng)了解了printf方法的所有特性。圖3-7給出了格式說(shuō)明符的語(yǔ)法圖。

控制流程

與任何程序設(shè)計(jì)語(yǔ)言一樣,Java使用條件語(yǔ)句和循環(huán)來(lái)確定控制流程。在本節(jié)中,先討論條件語(yǔ)句,然后再討論循環(huán)語(yǔ)句,最后再介紹顯得有些笨重的switch語(yǔ)句。當(dāng)需要對(duì)某個(gè)表達(dá)式的多個(gè)值進(jìn)行檢測(cè)時(shí),可以使用switch語(yǔ)句。

塊作用域

在深入學(xué)習(xí)控制結(jié)構(gòu)之前,需要了解塊(block)的概念。

塊(即復(fù)合語(yǔ)句)是指由一對(duì)花括號(hào)括起來(lái)的若干條簡(jiǎn)單的Java語(yǔ)句。塊確定了變量的作用域。一個(gè)塊可以嵌套在另一個(gè)塊中。下面就是在main方法塊中嵌套另一個(gè)語(yǔ)句塊的例子。

但是,不能在嵌套的兩個(gè)塊中聲明同名的變量。例如,下面的代碼就有錯(cuò)誤,而無(wú)法通過(guò)編譯:

條件語(yǔ)句

在Java中,條件語(yǔ)句的格式為

if (condition) statement

這里的條件必須用括號(hào)括起來(lái)。

與絕大多數(shù)程序設(shè)計(jì)語(yǔ)言一樣,Java常常希望在某個(gè)條件為真時(shí)執(zhí)行多條語(yǔ)句。在這種情況下,使用塊語(yǔ)句(block statement),格式為

{statement1statement2. . .}

例如:

if (yourSales >= target){performance = "Satisfactory";bonus = 100;}

當(dāng)yourSales大于或等于target時(shí),將執(zhí)行括號(hào)中的所有語(yǔ)句(請(qǐng)參看圖3-8)。在Java中,比較常見(jiàn)的條件語(yǔ)句格式如下所示(請(qǐng)參看圖3-9):

if (condition) statement1 else statement2

例如:

其中else部分是可選的。else與最鄰近的if構(gòu)成一組,因此,在語(yǔ)句

中else與第2個(gè)if配對(duì)。

重復(fù)地交替出現(xiàn)if…else if…是很常見(jiàn)的一種情況(請(qǐng)參看圖3-10)。例如:

循環(huán)

while循環(huán)當(dāng)條件為true時(shí)執(zhí)行一條語(yǔ)句(也可以是一個(gè)語(yǔ)句塊)。常用的格式為while (condition) statement如果開(kāi)始循環(huán)條件就為false,則循環(huán)體一次也不執(zhí)行請(qǐng)參看圖3-11)。

例3-3的程序?qū)⒂脕?lái)計(jì)算需要多長(zhǎng)時(shí)間能夠存儲(chǔ)特定數(shù)量的退休金。假定每年存入相同數(shù)量的金額,而且利率是固定的。

在這個(gè)例子中,增加了一個(gè)計(jì)數(shù)器,并在循環(huán)體中更新當(dāng)前的累積數(shù)量,直到總值超過(guò)目標(biāo)值為止。

(千萬(wàn)不要使用這個(gè)程序安排退休計(jì)劃。這里忽略了通貨膨脹和所期望的生活水準(zhǔn)。)

while循環(huán)語(yǔ)句首先檢測(cè)循環(huán)條件。因此,循環(huán)體中的代碼有可能不被執(zhí)行。如果希望循環(huán)體至少執(zhí)行一次,就應(yīng)該將檢測(cè)條件放置在最后。使用do/while循環(huán)語(yǔ)句可以實(shí)現(xiàn)這種操作方式。

它的語(yǔ)法格式為:

do statement while (condition);

這種循環(huán)語(yǔ)句先執(zhí)行語(yǔ)句(通常是一個(gè)語(yǔ)句塊),再檢測(cè)循環(huán)條件;然后重復(fù)語(yǔ)句,再檢測(cè)循環(huán)條件,以此類推。在例3-4的代碼中,首先計(jì)算退休賬戶中的余額,然后再詢問(wèn)是否打算退休:

只要用戶回答 “N”,循環(huán)就重復(fù)執(zhí)行(請(qǐng)參看圖3-12)。這是一個(gè)需要至少執(zhí)行一次的循環(huán)的很好例子,因?yàn)橛脩舯仨毾瓤吹接囝~才能知道是否滿足退休所用。

例3-3 Retirement.java

例3-4 Retirement2.java

確定循環(huán)

for循環(huán)語(yǔ)句是支持迭代的一種通用結(jié)構(gòu),使用每次迭代之后更新的計(jì)數(shù)器或類似的變量來(lái)控制迭代次數(shù)。如圖3-13所示,下面的程序?qū)?shù)字1~10輸出到屏幕上。

for (int i = 1; i <= 10; i++)

System.out.println(i);

for語(yǔ)句的第1部分通常用于對(duì)計(jì)數(shù)器初始化;第2部分給出每次循環(huán)前要檢測(cè)的循環(huán)條件;

第3部分指示如何更新計(jì)數(shù)器。

與C++一樣,盡管Java允許在for循環(huán)的各個(gè)部分放置任何表達(dá)式,但有一條不成文的規(guī)則:

for語(yǔ)句的3個(gè)部分應(yīng)該對(duì)同一個(gè)計(jì)數(shù)器變量進(jìn)行初始化、檢測(cè)和更新。若不遵守這一規(guī)則,編寫(xiě)的循環(huán)常常晦澀難懂。

即使遵守了這條規(guī)則,也還有可能出現(xiàn)很多問(wèn)題。例如,下面這個(gè)倒計(jì)數(shù)的循環(huán):

for (int i = 10; i > 0; i--)

System.out.println("Counting down . . . " + i);

System.out.println("Blastoff!");

當(dāng)在for語(yǔ)句的第1部分中聲明了一個(gè)變量之后,這個(gè)變量的作用域就為for循環(huán)的整個(gè)循環(huán)體。

尤其是,如果在for語(yǔ)句內(nèi)部定義一個(gè)變量,那么這個(gè)變量值不能在循環(huán)體外使用。因此,如果希望在for循環(huán)體之外使用循環(huán)計(jì)數(shù)器的最終值,就要確保這個(gè)變量在循環(huán)語(yǔ)句的前面且在外部聲明

另一方面,可以在獨(dú)立的不同for循環(huán)中定義同名的變量:

for循環(huán)語(yǔ)句只不過(guò)是while循環(huán)的一種便捷形式。例如

可以重寫(xiě)為:

例3-5給出了一個(gè)應(yīng)用for循環(huán)的典型例子。

這個(gè)程序用來(lái)計(jì)算抽獎(jiǎng)中獎(jiǎng)的概率。例如,如果必須從1~50之間的數(shù)字中取6個(gè)數(shù)字來(lái)抽獎(jiǎng),那么會(huì)有 (50×49×48×47×46×45)/(1×2×3×4×5×6) 種可能的結(jié)果,所以中獎(jiǎng)的幾率是1/15 890 700。祝你好運(yùn)!

一般情況下,如果從n個(gè)數(shù)字中抽取k個(gè)數(shù)字,那么會(huì)有下列公式得到的結(jié)果。

下面的for循環(huán)語(yǔ)句計(jì)算了上面這個(gè)公式的值:

例3-5 LotteryOdds.java

多重選擇—switch語(yǔ)句

在處理多個(gè)選項(xiàng)時(shí),使用if/else結(jié)構(gòu)顯得有些笨拙。Java有一個(gè)與C/C++完全一樣的switch語(yǔ)句。

例如,如果建立一個(gè)如圖3-14所示的包含4個(gè)選項(xiàng)的菜單系統(tǒng),就應(yīng)該使用下列代碼:

switch語(yǔ)句將從匹配值的case標(biāo)簽開(kāi)始執(zhí)行直到遇到break語(yǔ)句,或者執(zhí)行到switch語(yǔ)句的結(jié)束處為止。如果沒(méi)有匹配的case標(biāo)簽,而有default子句的話,就執(zhí)行這個(gè)子句。

注意,case標(biāo)簽必須是整數(shù)或枚舉常量,不能檢測(cè)字符串。

例如,下面這段代碼就存在錯(cuò)誤。

中斷控制流程語(yǔ)句

盡管Java的設(shè)計(jì)者將goto作為保留字,但實(shí)際上并沒(méi)有打算在語(yǔ)言中使用它。通常,人們認(rèn)為使用goto是一種拙劣的程序設(shè)計(jì)風(fēng)格。當(dāng)然,也有一些程序員認(rèn)為反對(duì)goto的呼聲似乎有些過(guò)分(例如,Donald Knuth就曾編著過(guò)一篇名為“Structured Programming with goto statements”的著名文章)。該文章說(shuō):無(wú)限制地使用goto語(yǔ)句確實(shí)是導(dǎo)致錯(cuò)誤的根源,但在有些情況下,偶爾使用goto跳出循環(huán)還是有益處的。Java設(shè)計(jì)者同意這種看法,甚至在Java語(yǔ)言中增加了一條帶標(biāo)簽的break,以此來(lái)支持這種程序設(shè)計(jì)風(fēng)格。

下面先來(lái)看看不帶標(biāo)簽的break語(yǔ)句。與用于退出switch語(yǔ)句的break語(yǔ)句一樣,它也可以用于退出循環(huán)。例如:

當(dāng)循環(huán)開(kāi)始時(shí)years>100,或者在循環(huán)中間balance≥goal時(shí)退出循環(huán)語(yǔ)句。當(dāng)然,也可以在不使用break的情況下計(jì)算years的值,如下所示:

但是需要注意,在這個(gè)版本中,檢測(cè)了兩次balance < goal。為了避免重復(fù)檢測(cè),有些程序員更加偏愛(ài)break語(yǔ)句。

與C++不同,Java還提供了一種帶標(biāo)簽的break語(yǔ)句,用于跳出多重嵌套的循環(huán)語(yǔ)句。有些時(shí)候,在嵌套很深的循環(huán)語(yǔ)句中會(huì)發(fā)生一些不可預(yù)料的事情。此時(shí)可能更加希望完全跳出嵌套的所有循環(huán)語(yǔ)句。通過(guò)添加一些額外的條件判斷來(lái)實(shí)現(xiàn)對(duì)各層循環(huán)的檢測(cè)是很不方便的。

這里有一個(gè)例子說(shuō)明了break語(yǔ)句的工作狀態(tài)。請(qǐng)注意,標(biāo)簽必須放置在最外層的循環(huán)之前,并且必須緊跟一個(gè)冒號(hào)。

如果輸入有誤,則通過(guò)執(zhí)行帶標(biāo)簽的break跳轉(zhuǎn)到帶標(biāo)簽的語(yǔ)句塊末尾。對(duì)于任何使用break的語(yǔ)句,都需要檢測(cè)循環(huán)是正常結(jié)束,還是通過(guò)break跳出。

因此,如果希望使用一條goto語(yǔ)句,并將一個(gè)標(biāo)簽放置在想要跳過(guò)的語(yǔ)句塊前面,就可以使用break語(yǔ)句!當(dāng)然,我們并不提倡使用這種方式。另外需要注意,只能跳出語(yǔ)句塊,而不能跳入語(yǔ)句塊。

最后,還有一個(gè)continue語(yǔ)句。與break語(yǔ)句一樣,它將中斷正常的控制流程。continue語(yǔ)句將控制轉(zhuǎn)移到最內(nèi)層循環(huán)的首部。例如:

如果n<0,則continue語(yǔ)句立刻跳到循環(huán)首部,越過(guò)了當(dāng)前迭代的其余部分。如果將continue語(yǔ)句用于for循環(huán)中,就可以跳到for循環(huán)的“更新”部分。例如,以下這個(gè)循環(huán):

如果n<0,則continue語(yǔ)句跳到count++語(yǔ)句。還有一種帶標(biāo)簽的continue語(yǔ)句,將跳到與標(biāo)簽匹配的循環(huán)首部。

覺(jué)得文章不錯(cuò)的話,可以轉(zhuǎn)發(fā)此文關(guān)注小編,之后持續(xù)更新干貨文章!!

總結(jié)

以上是生活随笔為你收集整理的java程序设计_80后程序员,带你深入理解Java基本的程序设计结构,不来你别后悔...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。