欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
Thinking in Java | CHAPTER 2


第2章 一切都是對象

“盡管以C++為基礎,但Java是一種更純粹的面向對象程序設計語(yǔ)言”。
無(wú)論C++還是Java都屬于雜合語(yǔ)言。但在Java中,設計者覺(jué)得這種雜合并不象在C++里那么重要。雜合語(yǔ)言允許采用多種編程風(fēng)格;之所以說(shuō)C++是一種雜合語(yǔ)言,是因為它支持與C語(yǔ)言的向后兼容能力。由于C++是C的一個(gè)超集,所以包含的許多特性都是后者不具備的,這些特性使C++在某些地方顯得過(guò)于復雜。
Java語(yǔ)言首先便假定了我們只希望進(jìn)行面向對象的程序設計。也就是說(shuō),正式用它設計之前,必須先將自己的思想轉入一個(gè)面向對象的世界(除非早已習慣了這個(gè)世界的思維方式)。只有做好這個(gè)準備工作,與其他OOP語(yǔ)言相比,才能體會(huì )到Java的易學(xué)易用。在本章,我們將探討Java程序的基本組件,并體會(huì )為什么說(shuō)Java乃至Java程序內的一切都是對象。

2.1 用句柄操縱對象
每種編程語(yǔ)言都有自己的數據處理方式。有些時(shí)候,程序員必須時(shí)刻留意準備處理的是什么類(lèi)型。您曾利用一些特殊語(yǔ)法直接操作過(guò)對象,或處理過(guò)一些間接表示的對象嗎(C或C++里的指針)?
所有這些在Java里都得到了簡(jiǎn)化,任何東西都可看作對象。因此,我們可采用一種統一的語(yǔ)法,任何地方均可照搬不誤。但要注意,盡管將一切都“看作”對象,但操縱的標識符實(shí)際是指向一個(gè)對象的“句柄”(Handle)。在其他Java參考書(shū)里,還可看到有的人將其稱(chēng)作一個(gè)“引用”,甚至一個(gè)“指針”??蓪⑦@一情形想象成用遙控板(句柄)操縱電視機(對象)。只要握住這個(gè)遙控板,就相當于掌握了與電視機連接的通道。但一旦需要“換頻道”或者“關(guān)小聲音”,我們實(shí)際操縱的是遙控板(句柄),再由遙控板自己操縱電視機(對象)。如果要在房間里四處走走,并想保持對電視機的控制,那么手上拿著(zhù)的是遙控板,而非電視機。
此外,即使沒(méi)有電視機,遙控板亦可獨立存在。也就是說(shuō),只是由于擁有一個(gè)句柄,并不表示必須有一個(gè)對象同它連接。所以如果想容納一個(gè)詞或句子,可創(chuàng )建一個(gè)String句柄:
String s;
但這里創(chuàng )建的只是句柄,并不是對象。若此時(shí)向s發(fā)送一條消息,就會(huì )獲得一個(gè)錯誤(運行期)。這是由于s實(shí)際并未與任何東西連接(即“沒(méi)有電視機”)。因此,一種更安全的做法是:創(chuàng )建一個(gè)句柄時(shí),記住無(wú)論如何都進(jìn)行初始化:
String s = "asdf";
然而,這里采用的是一種特殊類(lèi)型:字串可用加引號的文字初始化。通常,必須為對象使用一種更通用的初始化類(lèi)型。

2.2 所有對象都必須創(chuàng )建
創(chuàng )建句柄時(shí),我們希望它同一個(gè)新對象連接。通常用new關(guān)鍵字達到這一目的。new的意思是:“把我變成這些對象的一種新類(lèi)型”。所以在上面的例子中,可以說(shuō):
String s = new String("asdf");
它不僅指出“將我變成一個(gè)新字串”,也通過(guò)提供一個(gè)初始字串,指出了“如何生成這個(gè)新字串”。
當然,字串(String)并非唯一的類(lèi)型。Java配套提供了數量眾多的現成類(lèi)型。對我們來(lái)講,最重要的就是記住能自行創(chuàng )建類(lèi)型。事實(shí)上,這應是Java程序設計的一項基本操作,是繼續本書(shū)后余部分學(xué)習的基礎。

2.2.1 保存到什么地方
程序運行時(shí),我們最好對數據保存到什么地方做到心中有數。特別要注意的是內存的分配。有六個(gè)地方都可以保存數據:
(1) 寄存器。這是最快的保存區域,因為它位于和其他所有保存方式不同的地方:處理器內部。然而,寄存器的數量十分有限,所以寄存器是根據需要由編譯器分配。我們對此沒(méi)有直接的控制權,也不可能在自己的程序里找到寄存器存在的任何蹤跡。
(2) 堆棧。駐留于常規RAM(隨機訪(fǎng)問(wèn)存儲器)區域,但可通過(guò)它的“堆棧指針”獲得處理的直接支持。堆棧指針若向下移,會(huì )創(chuàng )建新的內存;若向上移,則會(huì )釋放那些內存。這是一種特別快、特別有效的數據保存方式,僅次于寄存器。創(chuàng )建程序時(shí),Java編譯器必須準確地知道堆棧內保存的所有數據的“長(cháng)度”以及“存在時(shí)間”。這是由于它必須生成相應的代碼,以便向上和向下移動(dòng)指針。這一限制無(wú)疑影響了程序的靈活性,所以盡管有些Java數據要保存在堆棧里——特別是對象句柄,但Java對象并不放到其中。
(3) 堆。一種常規用途的內存池(也在RAM區域),其中保存了Java對象。和堆棧不同,“內存堆”或“堆”(Heap)最吸引人的地方在于編譯器不必知道要從堆里分配多少存儲空間,也不必知道存儲的數據要在堆里停留多長(cháng)的時(shí)間。因此,用堆保存數據時(shí)會(huì )得到更大的靈活性。要求創(chuàng )建一個(gè)對象時(shí),只需用new命令編制相關(guān)的代碼即可。執行這些代碼時(shí),會(huì )在堆里自動(dòng)進(jìn)行數據的保存。當然,為達到這種靈活性,必然會(huì )付出一定的代價(jià):在堆里分配存儲空間時(shí)會(huì )花掉更長(cháng)的時(shí)間!
(4) 靜態(tài)存儲。這兒的“靜態(tài)”(Static)是指“位于固定位置”(盡管也在RAM里)。程序運行期間,靜態(tài)存儲的數據將隨時(shí)等候調用??捎胹tatic關(guān)鍵字指出一個(gè)對象的特定元素是靜態(tài)的。但Java對象本身永遠都不會(huì )置入靜態(tài)存儲空間。
(5) 常數存儲。常數值通常直接置于程序代碼內部。這樣做是安全的,因為它們永遠都不會(huì )改變。有的常數需要嚴格地保護,所以可考慮將它們置入只讀存儲器(ROM)。
(6) 非RAM存儲。若數據完全獨立于一個(gè)程序之外,則程序不運行時(shí)仍可存在,并在程序的控制范圍之外。其中兩個(gè)最主要的例子便是“流式對象”和“固定對象”。對于流式對象,對象會(huì )變成字節流,通常會(huì )發(fā)給另一臺機器。而對于固定對象,對象保存在磁盤(pán)中。即使程序中止運行,它們仍可保持自己的狀態(tài)不變。對于這些類(lèi)型的數據存儲,一個(gè)特別有用的技巧就是它們能存在于其他媒體中。一旦需要,甚至能將它們恢復成普通的、基于RAM的對象。Java 1.1提供了對Lightweight persistence的支持。未來(lái)的版本甚至可能提供更完整的方案。

2.2.2 特殊情況:主要類(lèi)型
有一系列類(lèi)需特別對待;可將它們想象成“基本”、“主要”或者“主”(Primitive)類(lèi)型,進(jìn)行程序設計時(shí)要頻繁用到它們。之所以要特別對待,是由于用new創(chuàng )建對象(特別是小的、簡(jiǎn)單的變量)并不是非常有效,因為new將對象置于“堆”里。對于這些類(lèi)型,Java采納了與C和C++相同的方法。也就是說(shuō),不是用new創(chuàng )建變量,而是創(chuàng )建一個(gè)并非句柄的“自動(dòng)”變量。這個(gè)變量容納了具體的值,并置于堆棧中,能夠更高效地存取。
Java決定了每種主要類(lèi)型的大小。就象在大多數語(yǔ)言里那樣,這些大小并不隨著(zhù)機器結構的變化而變化。這種大小的不可更改正是Java程序具有很強移植能力的原因之一。

主類(lèi)型

大小

最小值

最大值

封裝器類(lèi)型

boolean

1-bit



Boolean

char

16-bit

Unicode 0

Unicode 216- 1

Character

byte

8-bit

-128

+127

Byte[11]

short

16-bit

-215

+215 – 1

Short1

int

32-bit

-231

+231 – 1

Integer

long

64-bit

-263

+263 – 1

Long

float

32-bit

IEEE754

IEEE754

Float

double

64-bit

IEEE754

IEEE754

Double

void




Void1


①:到Java 1.1才有,1.0版沒(méi)有。

數值類(lèi)型全都是有符號(正負號)的,所以不必費勁尋找沒(méi)有符號的類(lèi)型。
主數據類(lèi)型也擁有自己的“封裝器”(wrapper)類(lèi)。這意味著(zhù)假如想讓堆內一個(gè)非主要對象表示那個(gè)主類(lèi)型,就要使用對應的封裝器。例如:
char c = ‘x‘;
Character C = new Character(‘c‘);
也可以直接使用:
Character C = new Character(‘x‘);
這樣做的原因將在以后的章節里解釋。

1. 高精度數字
Java 1.1增加了兩個(gè)類(lèi),用于進(jìn)行高精度的計算:BigInteger和BigDecimal。盡管它們大致可以劃分為“封裝器”類(lèi)型,但兩者都沒(méi)有對應的“主類(lèi)型”。
這兩個(gè)類(lèi)都有自己特殊的“方法”,對應于我們針對主類(lèi)型執行的操作。也就是說(shuō),能對int或float做的事情,對BigInteger和BigDecimal一樣可以做。只是必須使用方法調用,不能使用運算符。此外,由于牽涉更多,所以運算速度會(huì )慢一些。我們犧牲了速度,但換來(lái)了精度。
BigInteger支持任意精度的整數。也就是說(shuō),我們可精確表示任意大小的整數值,同時(shí)在運算過(guò)程中不會(huì )丟失任何信息。
BigDecimal支持任意精度的定點(diǎn)數字。例如,可用它進(jìn)行精確的幣值計算。
至于調用這兩個(gè)類(lèi)時(shí)可選用的構建器和方法,請自行參考聯(lián)機幫助文檔。

2.2.3 Java的數組
幾乎所有程序設計語(yǔ)言都支持數組。在C和C++里使用數組是非常危險的,因為那些數組只是內存塊。若程序訪(fǎng)問(wèn)自己內存塊以外的數組,或者在初始化之前使用內存(屬于常規編程錯誤),會(huì )產(chǎn)生不可預測的后果(注釋②)。

②:在C++里,應盡量不要使用數組,換用標準模板庫(Standard TemplateLibrary)里更安全的容器。

Java的一項主要設計目標就是安全性。所以在C和C++里困擾程序員的許多問(wèn)題都未在Java里重復。一個(gè)Java可以保證被初始化,而且不可在它的范圍之外訪(fǎng)問(wèn)。由于系統自動(dòng)進(jìn)行范圍檢查,所以必然要付出一些代價(jià):針對每個(gè)數組,以及在運行期間對索引的校驗,都會(huì )造成少量的內存開(kāi)銷(xiāo)。但由此換回的是更高的安全性,以及更高的工作效率。為此付出少許代價(jià)是值得的。
創(chuàng )建對象數組時(shí),實(shí)際創(chuàng )建的是一個(gè)句柄數組。而且每個(gè)句柄都會(huì )自動(dòng)初始化成一個(gè)特殊值,并帶有自己的關(guān)鍵字:null(空)。一旦Java看到null,就知道該句柄并未指向一個(gè)對象。正式使用前,必須為每個(gè)句柄都分配一個(gè)對象。若試圖使用依然為null的一個(gè)句柄,就會(huì )在運行期報告問(wèn)題。因此,典型的數組錯誤在Java里就得到了避免。
也可以創(chuàng )建主類(lèi)型數組。同樣地,編譯器能夠擔保對它的初始化,因為會(huì )將那個(gè)數組的內存劃分成零。
數組問(wèn)題將在以后的章節里詳細討論。

2.3 絕對不要清除對象
在大多數程序設計語(yǔ)言中,變量的“存在時(shí)間”(Lifetime)一直是程序員需要著(zhù)重考慮的問(wèn)題。變量應持續多長(cháng)的時(shí)間?如果想清除它,那么何時(shí)進(jìn)行?在變量存在時(shí)間上糾纏不清會(huì )造成大量的程序錯誤。在下面的小節里,將闡示Java如何幫助我們完成所有清除工作,從而極大了簡(jiǎn)化了這個(gè)問(wèn)題。

2.3.1 作用域
大多數程序設計語(yǔ)言都提供了“作用域”(Scope)的概念。對于在作用域里定義的名字,作用域同時(shí)決定了它的“可見(jiàn)性”以及“存在時(shí)間”。在C,C++和Java里,作用域是由花括號的位置決定的。參考下面這個(gè)例子:

{int x = 12;/* only x available */{int q = 96;/* both x & q available */}/* only x available *//* q “out of scope” */}

作為在作用域里定義的一個(gè)變量,它只有在那個(gè)作用域結束之前才可使用。
在上面的例子中,縮進(jìn)排版使Java代碼更易辨讀。由于Java是一種形式自由的語(yǔ)言,所以額外的空格、制表位以及回車(chē)都不會(huì )對結果程序造成影響。
注意盡管在C和C++里是合法的,但在Java里不能象下面這樣書(shū)寫(xiě)代碼:

{int x = 12;{int x = 96; /* illegal */}}

編譯器會(huì )認為變量x已被定義。所以C和C++能將一個(gè)變量“隱藏”在一個(gè)更大的作用域里。但這種做法在Java里是不允許的,因為Java的設計者認為這樣做使程序產(chǎn)生了混淆。

2.3.2 對象的作用域
Java對象不具備與主類(lèi)型一樣的存在時(shí)間。用new關(guān)鍵字創(chuàng )建一個(gè)Java對象的時(shí)候,它會(huì )超出作用域的范圍之外。所以假若使用下面這段代碼:

{
String s = new String("a string");
} /* 作用域的終點(diǎn) */

那么句柄s會(huì )在作用域的終點(diǎn)處消失。然而,s指向的String對象依然占據著(zhù)內存空間。在上面這段代碼里,我們沒(méi)有辦法訪(fǎng)問(wèn)對象,因為指向它的唯一一個(gè)句柄已超出了作用域的邊界。在后面的章節里,大家還會(huì )繼續學(xué)習如何在程序運行期間傳遞和復制對象句柄。
這樣造成的結果便是:對于用new創(chuàng )建的對象,只要我們愿意,它們就會(huì )一直保留下去。這個(gè)編程問(wèn)題在C和C++里特別突出??磥?lái)在C++里遇到的麻煩最大:由于不能從語(yǔ)言獲得任何幫助,所以在需要對象的時(shí)候,根本無(wú)法確定它們是否可用。而且更麻煩的是,在C++里,一旦工作完成,必須保證將對象清除。
這樣便帶來(lái)了一個(gè)有趣的問(wèn)題。假如Java讓對象依然故我,怎樣才能防止它們大量充斥內存,并最終造成程序的“凝固”呢。在C++里,這個(gè)問(wèn)題最令程序員頭痛。但Java以后,情況卻發(fā)生了改觀(guān)。Java有一個(gè)特別的“垃圾收集器”,它會(huì )查找用new創(chuàng )建的所有對象,并辨別其中哪些不再被引用。隨后,它會(huì )自動(dòng)釋放由那些閑置對象占據的內存,以便能由新對象使用。這意味著(zhù)我們根本不必操心內存的回收問(wèn)題。只需簡(jiǎn)單地創(chuàng )建對象,一旦不再需要它們,它們就會(huì )自動(dòng)離去。這樣做可防止在C++里很常見(jiàn)的一個(gè)編程問(wèn)題:由于程序員忘記釋放內存造成的“內存溢出”。

2.4 新建數據類(lèi)型:類(lèi)
如果說(shuō)一切東西都是對象,那么用什么決定一個(gè)“類(lèi)”(Class)的外觀(guān)與行為呢?換句話(huà)說(shuō),是什么建立起了一個(gè)對象的“類(lèi)型”(Type)呢?大家可能猜想有一個(gè)名為“type”的關(guān)鍵字。但從歷史看來(lái),大多數面向對象的語(yǔ)言都用關(guān)鍵字“class”表達這樣一個(gè)意思:“我準備告訴你對象一種新類(lèi)型的外觀(guān)”。class關(guān)鍵字太常用了,以至于本書(shū)許多地方并沒(méi)有用粗體字或雙引號加以強調。在這個(gè)關(guān)鍵字的后面,應該跟隨新數據類(lèi)型的名稱(chēng)。例如:
class ATypeName {/*類(lèi)主體置于這里}
這樣就引入了一種新類(lèi)型,接下來(lái)便可用new創(chuàng )建這種類(lèi)型的一個(gè)新對象:
ATypeName a = new ATypeName();
在A(yíng)TypeName里,類(lèi)主體只由一條注釋構成(星號和斜杠以及其中的內容,本章后面還會(huì )詳細講述),所以并不能對它做太多的事情。事實(shí)上,除非為其定義了某些方法,否則根本不能指示它做任何事情。

2.4.1 字段和方法
定義一個(gè)類(lèi)時(shí)(我們在Java里的全部工作就是定義類(lèi)、制作那些類(lèi)的對象以及將消息發(fā)給那些對象),可在自己的類(lèi)里設置兩種類(lèi)型的元素:數據成員(有時(shí)也叫“字段”)以及成員函數(通常叫“方法”)。其中,數據成員是一種對象(通過(guò)它的句柄與其通信),可以為任何類(lèi)型。它也可以是主類(lèi)型(并不是句柄)之一。如果是指向對象的一個(gè)句柄,則必須初始化那個(gè)句柄,用一種名為“構建器”(第4章會(huì )對此詳述)的特殊函數將其與一個(gè)實(shí)際對象連接起來(lái)(就象早先看到的那樣,使用new關(guān)鍵字)。但若是一種主類(lèi)型,則可在類(lèi)定義位置直接初始化(正如后面會(huì )看到的那樣,句柄亦可在定義位置初始化)。
每個(gè)對象都為自己的數據成員保有存儲空間;數據成員不會(huì )在對象之間共享。下面是定義了一些數據成員的類(lèi)示例:

class DataOnly {int i;float f;boolean b;}

這個(gè)類(lèi)并沒(méi)有做任何實(shí)質(zhì)性的事情,但我們可創(chuàng )建一個(gè)對象:
DataOnly d = new DataOnly();
可將值賦給數據成員,但首先必須知道如何引用一個(gè)對象的成員。為達到引用對象成員的目的,首先要寫(xiě)上對象句柄的名字,再跟隨一個(gè)點(diǎn)號(句點(diǎn)),再跟隨對象內部成員的名字。即“對象句柄.成員”。例如:
d.i = 47;
d.f = 1.1f;
d.b = false;
一個(gè)對象也可能包含了另一個(gè)對象,而另一個(gè)對象里則包含了我們想修改的數據。對于這個(gè)問(wèn)題,只需保持“連接句點(diǎn)”即可。例如:
myPlane.leftTank.capacity = 100;
除容納數據之外,DataOnly類(lèi)再也不能做更多的事情,因為它沒(méi)有成員函數(方法)。為正確理解工作原理,首先必須知道“自變量”和“返回值”的概念。我們馬上就會(huì )詳加解釋。

1. 主成員的默認值
若某個(gè)主數據類(lèi)型屬于一個(gè)類(lèi)成員,那么即使不明確(顯式)進(jìn)行初始化,也可以保證它們獲得一個(gè)默認值。

主類(lèi)型 默認值

Boolean false
Char ‘\u0000‘(null)
byte (byte)0
short (short)0
int 0
long 0L
float 0.0f
double 0.0d

一旦將變量作為類(lèi)成員使用,就要特別注意由Java分配的默認值。這樣做可保證主類(lèi)型的成員變量肯定得到了初始化(C++不具備這一功能),可有效遏止多種相關(guān)的編程錯誤。
然而,這種保證卻并不適用于“局部”變量——那些變量并非一個(gè)類(lèi)的字段。所以,假若在一個(gè)函數定義中寫(xiě)入下述代碼:
int x;
那么x會(huì )得到一些隨機值(這與C和C++是一樣的),不會(huì )自動(dòng)初始化成零。我們責任是在正式使用x前分配一個(gè)適當的值。如果忘記,就會(huì )得到一條編譯期錯誤,告訴我們變量可能尚未初始化。這種處理正是Java優(yōu)于C++的表現之一。許多C++編譯器會(huì )對變量未初始化發(fā)出警告,但在Java里卻是錯誤。

2.5 方法、自變量和返回值
迄今為止,我們一直用“函數”(Function)這個(gè)詞指代一個(gè)已命名的子例程。但在Java里,更常用的一個(gè)詞卻是“方法”(Method),代表“完成某事的途徑”。盡管它們表達的實(shí)際是同一個(gè)意思,但從現在開(kāi)始,本書(shū)將一直使用“方法”,而不是“函數”。
Java的“方法”決定了一個(gè)對象能夠接收的消息。通過(guò)本節的學(xué)習,大家會(huì )知道方法的定義有多么簡(jiǎn)單!
方法的基本組成部分包括名字、自變量、返回類(lèi)型以及主體。下面便是它最基本的形式:

返回類(lèi)型 方法名( /* 自變量列表*/ ) {/* 方法主體 */}

返回類(lèi)型是指調用方法之后返回的數值類(lèi)型。顯然,方法名的作用是對具體的方法進(jìn)行標識和引用。自變量列表列出了想傳遞給方法的信息類(lèi)型和名稱(chēng)。
Java的方法只能作為類(lèi)的一部分創(chuàng )建。只能針對某個(gè)對象調用一個(gè)方法(注釋③),而且那個(gè)對象必須能夠執行那個(gè)方法調用。若試圖為一個(gè)對象調用錯誤的方法,就會(huì )在編譯期得到一條出錯消息。為一個(gè)對象調用方法時(shí),需要先列出對象的名字,在后面跟上一個(gè)句點(diǎn),再跟上方法名以及它的參數列表。亦即“對象名.方法名(自變量1,自變量2,自變量3...)。舉個(gè)例子來(lái)說(shuō),假設我們有一個(gè)方法名叫f(),它沒(méi)有自變量,返回的是類(lèi)型為int的一個(gè)值。那么,假設有一個(gè)名為a的對象,可為其調用方法f(),則代碼如下:
int x = a.f();
返回值的類(lèi)型必須兼容x的類(lèi)型。
象這樣調用一個(gè)方法的行動(dòng)通常叫作“向對象發(fā)送一條消息”。在上面的例子中,消息是f(),而對象是a。面向對象的程序設計通常簡(jiǎn)單地歸納為“向對象發(fā)送消息”。

③:正如馬上就要學(xué)到的那樣,“靜態(tài)”方法可針對類(lèi)調用,毋需一個(gè)對象。

2.5.1 自變量列表
自變量列表規定了我們傳送給方法的是什么信息。正如大家或許已猜到的那樣,這些信息——如同Java內其他任何東西——采用的都是對象的形式。因此,我們必須在自變量列表里指定要傳遞的對象類(lèi)型,以及每個(gè)對象的名字。正如在Java其他地方處理對象時(shí)一樣,我們實(shí)際傳遞的是“句柄”(注釋④)。然而,句柄的類(lèi)型必須正確。倘若希望自變量是一個(gè)“字串”,那么傳遞的必須是一個(gè)字串。

④:對于前面提及的“特殊”數據類(lèi)型boolean,char,byte,short,int,long,,float以及double來(lái)說(shuō)是一個(gè)例外。但在傳遞對象時(shí),通常都是指傳遞指向對象的句柄。

下面讓我們考慮將一個(gè)字串作為自變量使用的方法。下面列出的是定義代碼,必須將它置于一個(gè)類(lèi)定義里,否則無(wú)法編譯:

int storage(String s) {
return s.length() * 2;
}

這個(gè)方法告訴我們需要多少字節才能容納一個(gè)特定字串里的信息(字串里的每個(gè)字符都是16位,或者說(shuō)2個(gè)字節、長(cháng)整數,以便提供對Unicode字符的支持)。自變量的類(lèi)型為String,而且叫作s。一旦將s傳遞給方法,就可將它當作其他對象一樣處理(可向其發(fā)送消息)。在這里,我們調用的是length()方法,它是String的方法之一。該方法返回的是一個(gè)字串里的字符數。
通過(guò)上面的例子,也可以了解return關(guān)鍵字的運用。它主要做兩件事情。首先,它意味著(zhù)“離開(kāi)方法,我已完工了”。其次,假設方法生成了一個(gè)值,則那個(gè)值緊接在return語(yǔ)句的后面。在這種情況下,返回值是通過(guò)計算表達式“s.length()*2”而產(chǎn)生的。
可按自己的愿望返回任意類(lèi)型,但倘若不想返回任何東西,就可指示方法返回void(空)。下面列出一些例子。

boolean flag() { return true; }
float naturalLogBase() { return 2.718; }
void nothing() { return; }
void nothing2() {}

若返回類(lèi)型為void,則return關(guān)鍵字唯一的作用就是退出方法。所以一旦抵達方法末尾,該關(guān)鍵字便不需要了??稍谌魏蔚胤綇囊粋€(gè)方法返回。但假設已指定了一種非void的返回類(lèi)型,那么無(wú)論從何地返回,編譯器都會(huì )確保我們返回的是正確的類(lèi)型。
到此為止,大家或許已得到了這樣的一個(gè)印象:一個(gè)程序只是一系列對象的集合,它們的方法將其他對象作為自己的自變量使用,而且將消息發(fā)給那些對象。這種說(shuō)法大體正確,但通過(guò)以后的學(xué)習,大家還會(huì )知道如何在一個(gè)方法里作出決策,做一些更細致的基層工作。至于這一章,只需理解消息傳送就足夠了。

2.6 構建Java程序
正式構建自己的第一個(gè)Java程序前,還有幾個(gè)問(wèn)題需要注意。

2.6.1 名字的可見(jiàn)性
在所有程序設計語(yǔ)言里,一個(gè)不可避免的問(wèn)題是對名字或名稱(chēng)的控制。假設您在程序的某個(gè)模塊里使用了一個(gè)名字,而另一名程序員在另一個(gè)模塊里使用了相同的名字。此時(shí),如何區分兩個(gè)名字,并防止兩個(gè)名字互相沖突呢?這個(gè)問(wèn)題在C語(yǔ)言里特別突出。因為程序未提供很好的名字管理方法。C++的類(lèi)(即Java類(lèi)的基礎)嵌套使用類(lèi)里的函數,使其不至于同其他類(lèi)里的嵌套函數名沖突。然而,C++仍然允許使用全局數據以及全局函數,所以仍然難以避免沖突。為解決這個(gè)問(wèn)題,C++用額外的關(guān)鍵字引入了“命名空間”的概念。
由于采用全新的機制,所以Java能完全避免這些問(wèn)題。為了給一個(gè)庫生成明確的名字,采用了與Internet域名類(lèi)似的名字。事實(shí)上,Java的設計者鼓勵程序員反轉使用自己的Internet域名,因為它們肯定是獨一無(wú)二的。由于我的域名是BruceEckel.com,所以我的實(shí)用工具庫就可命名為com.bruceeckel.utility.foibles。反轉了域名后,可將點(diǎn)號想象成子目錄。
在Java 1.0和Java 1.1中,域擴展名com,edu,org,net等都約定為大寫(xiě)形式。所以庫的樣子就變成:COM.bruceeckel.utility.foibles。然而,在Java 1.2的開(kāi)發(fā)過(guò)程中,設計者發(fā)現這樣做會(huì )造成一些問(wèn)題。所以目前的整個(gè)軟件包都以小寫(xiě)字母為標準。
Java的這種特殊機制意味著(zhù)所有文件都自動(dòng)存在于自己的命名空間里。而且一個(gè)文件里的每個(gè)類(lèi)都自動(dòng)獲得一個(gè)獨一無(wú)二的標識符(當然,一個(gè)文件里的類(lèi)名必須是唯一的)。所以不必學(xué)習特殊的語(yǔ)言知識來(lái)解決這個(gè)問(wèn)題——語(yǔ)言本身已幫我們照顧到這一點(diǎn)。

2.6.2 使用其他組件
一旦要在自己的程序里使用一個(gè)預先定義好的類(lèi),編譯器就必須知道如何找到它。當然,這個(gè)類(lèi)可能就在發(fā)出調用的那個(gè)相同的源碼文件里。如果是那種情況,只需簡(jiǎn)單地使用這個(gè)類(lèi)即可——即使它直到文件的后面仍未得到定義。Java消除了“向前引用”的問(wèn)題,所以不要關(guān)心這些事情。
但假若那個(gè)類(lèi)位于其他文件里呢?您或許認為編譯器應該足夠“聯(lián)盟”,可以自行發(fā)現它。但實(shí)情并非如此。假設我們想使用一個(gè)具有特定名稱(chēng)的類(lèi),但那個(gè)類(lèi)的定義位于多個(gè)文件里?;蛘吒?,假設我們準備寫(xiě)一個(gè)程序,但在創(chuàng )建它的時(shí)候,卻向自己的庫加入了一個(gè)新類(lèi),它與現有某個(gè)類(lèi)的名字發(fā)生了沖突。
為解決這個(gè)問(wèn)題,必須消除所有潛在的、糾纏不清的情況。為達到這個(gè)目的,要用import關(guān)鍵字準確告訴Java編譯器我們希望的類(lèi)是什么。import的作用是指示編譯器導入一個(gè)“包”——或者說(shuō)一個(gè)“類(lèi)庫”(在其他語(yǔ)言里,可將“庫”想象成一系列函數、數據以及類(lèi)的集合。但請記住,Java的所有代碼都必須寫(xiě)入一個(gè)類(lèi)中)。
大多數時(shí)候,我們直接采用來(lái)自標準Java庫的組件(部件)即可,它們是與編譯器配套提供的。使用這些組件時(shí),沒(méi)有必要關(guān)心冗長(cháng)的保留域名;舉個(gè)例子來(lái)說(shuō),只需象下面這樣寫(xiě)一行代碼即可:
import java.util.Vector;
它的作用是告訴編譯器我們想使用Java的Vector類(lèi)。然而,util包含了數量眾多的類(lèi),我們有時(shí)希望使用其中的幾個(gè),同時(shí)不想全部明確地聲明它們。為達到這個(gè)目的,可使用“*”通配符。如下所示:
import java.util.*;
需導入一系列類(lèi)時(shí),采用的通常是這個(gè)辦法。應盡量避免一個(gè)一個(gè)地導入類(lèi)。

2.6.3 static關(guān)鍵字
通常,我們創(chuàng )建類(lèi)時(shí)會(huì )指出那個(gè)類(lèi)的對象的外觀(guān)與行為。除非用new創(chuàng )建那個(gè)類(lèi)的一個(gè)對象,否則實(shí)際上并未得到任何東西。只有執行了new后,才會(huì )正式生成數據存儲空間,并可使用相應的方法。
但在兩種特殊的情形下,上述方法并不堪用。一種情形是只想用一個(gè)存儲區域來(lái)保存一個(gè)特定的數據——無(wú)論要創(chuàng )建多少個(gè)對象,甚至根本不創(chuàng )建對象。另一種情形是我們需要一個(gè)特殊的方法,它沒(méi)有與這個(gè)類(lèi)的任何對象關(guān)聯(lián)。也就是說(shuō),即使沒(méi)有創(chuàng )建對象,也需要一個(gè)能調用的方法。為滿(mǎn)足這兩方面的要求,可使用static(靜態(tài))關(guān)鍵字。一旦將什么東西設為static,數據或方法就不會(huì )同那個(gè)類(lèi)的任何對象實(shí)例聯(lián)系到一起。所以盡管從未創(chuàng )建那個(gè)類(lèi)的一個(gè)對象,仍能調用一個(gè)static方法,或訪(fǎng)問(wèn)一些static數據。而在這之前,對于非static數據和方法,我們必須創(chuàng )建一個(gè)對象,并用那個(gè)對象訪(fǎng)問(wèn)數據或方法。這是由于非static數據和方法必須知道它們操作的具體對象。當然,在正式使用前,由于static方法不需要創(chuàng )建任何對象,所以它們不可簡(jiǎn)單地調用其他那些成員,同時(shí)不引用一個(gè)已命名的對象,從而直接訪(fǎng)問(wèn)非static成員或方法(因為非static成員和方法必須同一個(gè)特定的對象關(guān)聯(lián)到一起)。
有些面向對象的語(yǔ)言使用了“類(lèi)數據”和“類(lèi)方法”這兩個(gè)術(shù)語(yǔ)。它們意味著(zhù)數據和方法只是為作為一個(gè)整體的類(lèi)而存在的,并不是為那個(gè)類(lèi)的任何特定對象。有時(shí),您會(huì )在其他一些Java書(shū)刊里發(fā)現這樣的稱(chēng)呼。
為了將數據成員或方法設為static,只需在定義前置和這個(gè)關(guān)鍵字即可。例如,下述代碼能生成一個(gè)static數據成員,并對其初始化:

class StaticTest {
Static int i = 47;
}

現在,盡管我們制作了兩個(gè)StaticTest對象,但它們仍然只占據StaticTest.i的一個(gè)存儲空間。這兩個(gè)對象都共享同樣的i。請考察下述代碼:
StaticTest st1 = new StaticTest();
StaticTest st2 = new StaticTest();
此時(shí),無(wú)論st1.i還是st2.i都有同樣的值47,因為它們引用的是同樣的內存區域。
有兩個(gè)辦法可引用一個(gè)static變量。正如上面展示的那樣,可通過(guò)一個(gè)對象命名它,如st2.i。亦可直接用它的類(lèi)名引用,而這在非靜態(tài)成員里是行不通的(最好用這個(gè)辦法引用static變量,因為它強調了那個(gè)變量的“靜態(tài)”本質(zhì))。
StaticTest.i++;
其中,++運算符會(huì )使變量增值。此時(shí),無(wú)論st1.i還是st2.i的值都是48。
類(lèi)似的邏輯也適用于靜態(tài)方法。既可象對其他任何方法那樣通過(guò)一個(gè)對象引用靜態(tài)方法,亦可用特殊的語(yǔ)法格式“類(lèi)名.方法()”加以引用。靜態(tài)方法的定義是類(lèi)似的:
class StaticFun {
static void incr() { StaticTest.i++; }
}
從中可看出,StaticFun的方法incr()使靜態(tài)數據i增值。通過(guò)對象,可用典型的方法調用incr():
StaticFun sf = new StaticFun();
sf.incr();
或者,由于incr()是一種靜態(tài)方法,所以可通過(guò)它的類(lèi)直接調用:
StaticFun.incr();
盡管是“靜態(tài)”的,但只要應用于一個(gè)數據成員,就會(huì )明確改變數據的創(chuàng )建方式(一個(gè)類(lèi)一個(gè)成員,以及每個(gè)對象一個(gè)非靜態(tài)成員)。若應用于一個(gè)方法,就沒(méi)有那么戲劇化了。對方法來(lái)說(shuō),static一項重要的用途就是幫助我們在不必創(chuàng )建對象的前提下調用那個(gè)方法。正如以后會(huì )看到的那樣,這一點(diǎn)是至關(guān)重要的——特別是在定義程序運行入口方法main()的時(shí)候。
和其他任何方法一樣,static方法也能創(chuàng )建自己類(lèi)型的命名對象。所以經(jīng)常把static方法作為一個(gè)“領(lǐng)頭羊”使用,用它生成一系列自己類(lèi)型的“實(shí)例”。

2.7 我們的第一個(gè)Java程序
最后,讓我們正式編一個(gè)程序(注釋⑤)。它能打印出與當前運行的系統有關(guān)的資料,并利用了來(lái)自Java標準庫的System對象的多種方法。注意這里引入了一種額外的注釋樣式:“//”。它表示到本行結束前的所有內容都是注釋?zhuān)?br>
// Property.javaimport java.util.*;public class Property {public static void main(String[] args) {System.out.println(new Date());Properties p = System.getProperties();p.list(System.out);System.out.println("--- Memory Usage:");Runtime rt = Runtime.getRuntime();System.out.println("Total Memory = "+ rt.totalMemory()+ " Free Memory = "+ rt.freeMemory());}}

⑤:在某些編程環(huán)境里,程序會(huì )在屏幕上一切而過(guò),甚至沒(méi)機會(huì )看到結果??蓪⑾旅孢@段代碼置于main()的末尾,用它暫停輸出:
try {
Thread.currentThread().sleep(5 * 1000);
} catch(InterruptedException e) {}
}
它的作用是暫停輸出5秒鐘。這段代碼涉及的一些概念要到本書(shū)后面才會(huì )講到。所以目前不必深究,只知道它是讓程序暫停的一個(gè)技巧便可。


在每個(gè)程序文件的開(kāi)頭,都必須放置一個(gè)import語(yǔ)句,導入那個(gè)文件的代碼里要用到的所有額外的類(lèi)。注意我們說(shuō)它們是“額外”的,因為一個(gè)特殊的類(lèi)庫會(huì )自動(dòng)導入每個(gè)Java文件:java.lang。啟動(dòng)您的Web瀏覽器,查看由Sun提供的用戶(hù)文檔(如果尚未從http://www.java.sun.com下載,或用其他方式安裝了Java文檔,請立即下載)。在packages.html文件里,可找到Java配套提供的所有類(lèi)庫名稱(chēng)。請選擇其中的java.lang。在“Class Index”下面,可找到屬于那個(gè)庫的全部類(lèi)的列表。由于java.lang默認進(jìn)入每個(gè)Java代碼文件,所以這些類(lèi)在任何時(shí)候都可直接使用。在這個(gè)列表里,可發(fā)現System和Runtime,我們在Property.java里用到了它們。java.lang里沒(méi)有列出Date類(lèi),所以必須導入另一個(gè)類(lèi)庫才能使用它。如果不清楚一個(gè)特定的類(lèi)在哪個(gè)類(lèi)庫里,或者想檢視所有的類(lèi),可在Java用戶(hù)文檔里選擇“Class Hierarchy”(類(lèi)分級結構)。在Web瀏覽器中,雖然要花不短的時(shí)間來(lái)建立這個(gè)結構,但可清楚找到與Java配套提供的每一個(gè)類(lèi)。隨后,可用瀏覽器的“查找”(Find)功能搜索關(guān)鍵字“Date”。經(jīng)這樣處理后,可發(fā)現我們的搜索目標以java.util.Date的形式列出。我們終于知道它位于util庫里,所以必須導入java.util.*;否則便不能使用Date。
觀(guān)察packages.html文檔最開(kāi)頭的部分(我已將其設為自己的默認起始頁(yè)),請選擇java.lang,再選System。這時(shí)可看到System類(lèi)有幾個(gè)字段。若選擇out,就可知道它是一個(gè)static PrintStream對象。由于它是“靜態(tài)”的,所以不需要我們創(chuàng )建任何東西。out對象肯定是3,所以只需直接用它即可。我們能對這個(gè)out對象做的事情由它的類(lèi)型決定:PrintStream。PrintStream在說(shuō)明文字中以一個(gè)超鏈接的形式列出,這一點(diǎn)做得非常方便。所以假若單擊那個(gè)鏈接,就可看到能夠為PrintStream調用的所有方法。方法的數量不少,本書(shū)后面會(huì )詳細介紹。就目前來(lái)說(shuō),我們感興趣的只有println()。它的意思是“把我給你的東西打印到控制臺,并用一個(gè)新行結束”。所以在任何Java程序中,一旦要把某些內容打印到控制臺,就可條件反射地寫(xiě)上System.out.println("內容")。
類(lèi)名與文件是一樣的。若象現在這樣創(chuàng )建一個(gè)獨立的程序,文件中的一個(gè)類(lèi)必須與文件同名(如果沒(méi)這樣做,編譯器會(huì )及時(shí)作出反應)。類(lèi)里必須包含一個(gè)名為main()的方法,形式如下:
public static void main(String[] args) {
其中,關(guān)鍵字“public”意味著(zhù)方法可由外部世界調用(第5章會(huì )詳細解釋?zhuān)?。main()的自變量是包含了String對象的一個(gè)數組。args不會(huì )在本程序中用到,但需要在這個(gè)地方列出,因為它們保存了在命令行調用的自變量。
程序的第一行非常有趣:
System.out.println(new Date());
請觀(guān)察它的自變量:創(chuàng )建Date對象唯一的目的就是將它的值發(fā)送給println()。一旦這個(gè)語(yǔ)句執行完畢,Date就不再需要。隨之而來(lái)的“垃圾收集器”會(huì )發(fā)現這一情況,并在任何可能的時(shí)候將其回收。事實(shí)上,我們沒(méi)太大的必要關(guān)心“清除”的細節。
第二行調用了System.getProperties()。若用Web瀏覽器查看聯(lián)機用戶(hù)文檔,就可知道getProperties()是System類(lèi)的一個(gè)static方法。由于它是“靜態(tài)”的,所以不必創(chuàng )建任何對象便可調用該方法。無(wú)論是否存在該類(lèi)的一個(gè)對象,static方法隨時(shí)都可使用。調用getProperties()時(shí),它會(huì )將系統屬性作為Properties類(lèi)的一個(gè)對象生成(注意Properties是“屬性”的意思)。隨后的的句柄保存在一個(gè)名為p的Properties句柄里。在第三行,大家可看到Properties對象有一個(gè)名為list()的方法,它將自己的全部?jì)热荻及l(fā)給一個(gè)我們作為自變量傳遞的PrintStream對象。
main()的第四和第六行是典型的打印語(yǔ)句。注意為了打印多個(gè)String值,用加號(+)分隔它們即可。然而,也要在這里注意一些奇怪的事情。在String對象中使用時(shí),加號并不代表真正的“相加”。處理字串時(shí),我們通常不必考慮“+”的任何特殊含義。但是,Java的String類(lèi)要受一種名為“運算符過(guò)載”的機制的制約。也就是說(shuō),只有在隨同String對象使用時(shí),加號才會(huì )產(chǎn)生與其他任何地方不同的表現。對于字串,它的意思是“連接這兩個(gè)字串”。
但事情到此并未結束。請觀(guān)察下述語(yǔ)句:
System.out.println("Total Memory = "
+ rt.totalMemory()
+ " Free Memory = "
+ rt.freeMemory());
其中,totalMemory()和freeMemory()返回的是數值,并非String對象。如果將一個(gè)數值“加”到一個(gè)字串身上,會(huì )發(fā)生什么情況呢?同我們一樣,編譯器也會(huì )意識到這個(gè)問(wèn)題,并魔術(shù)般地調用一個(gè)方法,將那個(gè)數值(int,float等等)轉換成字串。經(jīng)這樣處理后,它們當然能利用加號“加”到一起。這種“自動(dòng)類(lèi)型轉換”亦劃入“運算符過(guò)載”處理的范疇。
許多Java著(zhù)作都在熱烈地辯論“運算符過(guò)載”(C++的一項特性)是否有用。目前就是反對它的一個(gè)好例子!然而,這最多只能算編譯器(程序)的問(wèn)題,而且只是對String對象而言。對于自己編寫(xiě)的任何源代碼,都不可能使運算符“過(guò)載”。
通過(guò)為Runtime類(lèi)調用getRuntime()方法,main()的第五行創(chuàng )建了一個(gè)Runtime對象。返回的則是指向一個(gè)Runtime對象的句柄。而且,我們不必關(guān)心它是一個(gè)靜態(tài)對象,還是由new命令創(chuàng )建的一個(gè)對象。這是由于我們不必為清除工作負責,可以大模大樣地使用對象。正如顯示的那樣,Runtime可告訴我們與內存使用有關(guān)的信息。

2.8 注釋和嵌入文檔
Java里有兩種類(lèi)型的注釋。第一種是傳統的、C語(yǔ)言風(fēng)格的注釋?zhuān)菑腃++繼承而來(lái)的。這些注釋用一個(gè)“/*”起頭,隨后是注釋內容,并可跨越多行,最后用一個(gè)“*/”結束。注意許多程序員在連續注釋內容的每一行都用一個(gè)“*”開(kāi)頭,所以經(jīng)常能看到象下面這樣的內容:

/* 這是
* 一段注釋?zhuān)?br>* 它跨越了多個(gè)行
*/

但請記住,進(jìn)行編譯時(shí),/*和*/之間的所有東西都會(huì )被忽略,所以上述注釋與下面這段注釋并沒(méi)有什么不同:

/* 這是一段注釋?zhuān)?br>它跨越了多個(gè)行 */

第二種類(lèi)型的注釋也起源于C++。這種注釋叫作“單行注釋”,以一個(gè)“//”起頭,表示這一行的所有內容都是注釋。這種類(lèi)型的注釋更常用,因為它書(shū)寫(xiě)時(shí)更方便。沒(méi)有必要在鍵盤(pán)上尋找“/”,再尋找“*”(只需按同樣的鍵兩次),而且不必在注釋結尾時(shí)加一個(gè)結束標記。下面便是這類(lèi)注釋的一個(gè)例子:

// 這是一條單行注釋


2.8.1 注釋文檔
對于Java語(yǔ)言,最體貼的一項設計就是它并沒(méi)有打算讓人們?yōu)榱藢?xiě)程序而寫(xiě)程序——人們也需要考慮程序的文檔化問(wèn)題。對于程序的文檔化,最大的問(wèn)題莫過(guò)于對文檔的維護。若文檔與代碼分離,那么每次改變代碼后都要改變文檔,這無(wú)疑會(huì )變成相當麻煩的一件事情。解決的方法看起來(lái)似乎很簡(jiǎn)單:將代碼同文檔“鏈接”起來(lái)。為達到這個(gè)目的,最簡(jiǎn)單的方法是將所有內容都置于同一個(gè)文件。然而,為使一切都整齊劃一,還必須使用一種特殊的注釋語(yǔ)法,以便標記出特殊的文檔;另外還需要一個(gè)工具,用于提取這些注釋?zhuān)从袃r(jià)值的形式將其展現出來(lái)。這些都是Java必須做到的。
用于提取注釋的工具叫作javadoc。它采用了部分來(lái)自Java編譯器的技術(shù),查找我們置入程序的特殊注釋標記。它不僅提取由這些標記指示的信息,也將毗鄰注釋的類(lèi)名或方法名提取出來(lái)。這樣一來(lái),我們就可用最輕的工作量,生成十分專(zhuān)業(yè)的程序文檔。
javadoc輸出的是一個(gè)HTML文件,可用自己的Web瀏覽器查看。該工具允許我們創(chuàng )建和管理單個(gè)源文件,并生動(dòng)生成有用的文檔。由于有了jvadoc,所以我們能夠用標準的方法創(chuàng )建文檔。而且由于它非常方便,所以我們能輕松獲得所有Java庫的文檔。

2.8.2 具體語(yǔ)法
所有javadoc命令都只能出現于“/**”注釋中。但和平常一樣,注釋結束于一個(gè)“*/”。主要通過(guò)兩種方式來(lái)使用javadoc:嵌入的HTML,或使用“文檔標記”。其中,“文檔標記”(Doc tags)是一些以“@”開(kāi)頭的命令,置于注釋行的起始處(但前導的“*”會(huì )被忽略)。
有三種類(lèi)型的注釋文檔,它們對應于位于注釋后面的元素:類(lèi)、變量或者方法。也就是說(shuō),一個(gè)類(lèi)注釋正好位于一個(gè)類(lèi)定義之前;變量注釋正好位于變量定義之前;而一個(gè)方法定義正好位于一個(gè)方法定義的前面。如下面這個(gè)簡(jiǎn)單的例子所示:

/** 一個(gè)類(lèi)注釋 */
public class docTest {
/** 一個(gè)變量注釋 */
public int i;
/** 一個(gè)方法注釋 */
public void f() {}
}

注意javadoc只能為public(公共)和protected(受保護)成員處理注釋文檔。“private”(私有)和“友好”(詳見(jiàn)5章)成員的注釋會(huì )被忽略,我們看不到任何輸出(也可以用-private標記包括private成員)。這樣做是有道理的,因為只有public和protected成員才可在文件之外使用,這是客戶(hù)程序員的希望。然而,所有類(lèi)注釋都會(huì )包含到輸出結果里。
上述代碼的輸出是一個(gè)HTML文件,它與其他Java文檔具有相同的標準格式。因此,用戶(hù)會(huì )非常熟悉這種格式,可在您設計的類(lèi)中方便地“漫游”。設計程序時(shí),請務(wù)必考慮輸入上述代碼,用javadoc處理一下,觀(guān)看最終HTML文件的效果如何。

2.8.3 嵌入HTML
javadoc將HTML命令傳遞給最終生成的HTML文檔。這便使我們能夠充分利用HTML的巨大威力。當然,我們的最終動(dòng)機是格式化代碼,不是為了嘩眾取寵。下面列出一個(gè)例子:

/**
* <pre>
* System.out.println(new Date());
* </pre>
*/

亦可象在其他Web文檔里那樣運用HTML,對普通文本進(jìn)行格式化,使其更具條理、更加美觀(guān):

/**
* 您<em>甚至</em>可以插入一個(gè)列表:
* <ol>
* <li> 項目一
* <li> 項目二
* <li> 項目三
* </ol>
*/

注意在文檔注釋中,位于一行最開(kāi)頭的星號會(huì )被javadoc丟棄。同時(shí)丟棄的還有前導空格。javadoc會(huì )對所有內容進(jìn)行格式化,使其與標準的文檔外觀(guān)相符。不要將<h1>或<hr>這樣的標題當作嵌入HTML使用,因為javadoc會(huì )插入自己的標題,我們給出的標題會(huì )與之沖撞。
所有類(lèi)型的注釋文檔——類(lèi)、變量和方法——都支持嵌入HTML。

2.8.4 @see:引用其他類(lèi)
所有三種類(lèi)型的注釋文檔都可包含@see標記,它允許我們引用其他類(lèi)里的文檔。對于這個(gè)標記,javadoc會(huì )生成相應的HTML,將其直接鏈接到其他文檔。格式如下:

@see 類(lèi)名
@see 完整類(lèi)名
@see 完整類(lèi)名#方法名

每一格式都會(huì )在生成的文檔里自動(dòng)加入一個(gè)超鏈接的“See Also”(參見(jiàn))條目。注意javadoc不會(huì )檢查我們指定的超鏈接,不會(huì )驗證它們是否有效。

2.8.5 類(lèi)文檔標記
隨同嵌入HTML和@see引用,類(lèi)文檔還可以包括用于版本信息以及作者姓名的標記。類(lèi)文檔亦可用于“接口”目的(本書(shū)后面會(huì )詳細解釋?zhuān)?br>
1. @version
格式如下:
@version 版本信息
其中,“版本信息”代表任何適合作為版本說(shuō)明的資料。若在javadoc命令行使用了“-version”標記,就會(huì )從生成的HTML文檔里提取出版本信息。

2. @author
格式如下:
@author 作者信息
其中,“作者信息”包括您的姓名、電子函件地址或者其他任何適宜的資料。若在javadoc命令行使用了“-author”標記,就會(huì )專(zhuān)門(mén)從生成的HTML文檔里提取出作者信息。
可為一系列作者使用多個(gè)這樣的標記,但它們必須連續放置。全部作者信息會(huì )一起存入最終HTML代碼的單獨一個(gè)段落里。

2.8.6 變量文檔標記
變量文檔只能包括嵌入的HTML以及@see引用。

2.8.7 方法文檔標記
除嵌入HTML和@see引用之外,方法還允許使用針對參數、返回值以及違例的文檔標記。

1. @param
格式如下:
@param 參數名 說(shuō)明
其中,“參數名”是指參數列表內的標識符,而“說(shuō)明”代表一些可延續到后續行內的說(shuō)明文字。一旦遇到一個(gè)新文檔標記,就認為前一個(gè)說(shuō)明結束??墒褂萌我鈹盗康恼f(shuō)明,每個(gè)參數一個(gè)。

2. @return
格式如下:
@return 說(shuō)明
其中,“說(shuō)明”是指返回值的含義。它可延續到后面的行內。

3. @exception
有關(guān)“違例”(Exception)的詳細情況,我們會(huì )在第9章講述。簡(jiǎn)言之,它們是一些特殊的對象,若某個(gè)方法失敗,就可將它們“扔出”對象。調用一個(gè)方法時(shí),盡管只有一個(gè)違例對象出現,但一些特殊的方法也許能產(chǎn)生任意數量的、不同類(lèi)型的違例。所有這些違例都需要說(shuō)明。所以,違例標記的格式如下:
@exception 完整類(lèi)名 說(shuō)明
其中,“完整類(lèi)名”明確指定了一個(gè)違例類(lèi)的名字,它是在其他某個(gè)地方定義好的。而“說(shuō)明”(同樣可以延續到下面的行)告訴我們?yōu)槭裁催@種特殊類(lèi)型的違例會(huì )在方法調用中出現。

4. @deprecated
這是Java 1.1的新特性。該標記用于指出一些舊功能已由改進(jìn)過(guò)的新功能取代。該標記的作用是建議用戶(hù)不必再使用一種特定的功能,因為未來(lái)改版時(shí)可能摒棄這一功能。若將一個(gè)方法標記為@deprecated,則使用該方法時(shí)會(huì )收到編譯器的警告。

2.8.8 文檔示例
下面還是我們的第一個(gè)Java程序,只不過(guò)已加入了完整的文檔注釋?zhuān)?br>
92頁(yè)程序

第一行:
//: Property.java
采用了我自己的方法:將一個(gè)“:”作為特殊的記號,指出這是包含了源文件名字的一個(gè)注釋行。最后一行也用這樣的一條注釋結尾,它標志著(zhù)源代碼清單的結束。這樣一來(lái),可將代碼從本書(shū)的正文中方便地提取出來(lái),并用一個(gè)編譯器檢查。這方面的細節在第17章講述。

2.9 編碼樣式
一個(gè)非正式的Java編程標準是大寫(xiě)一個(gè)類(lèi)名的首字母。若類(lèi)名由幾個(gè)單詞構成,那么把它們緊靠到一起(也就是說(shuō),不要用下劃線(xiàn)來(lái)分隔名字)。此外,每個(gè)嵌入單詞的首字母都采用大寫(xiě)形式。例如:
class AllTheColorsOfTheRainbow { // ...}
對于其他幾乎所有內容:方法、字段(成員變量)以及對象句柄名稱(chēng),可接受的樣式與類(lèi)樣式差不多,只是標識符的第一個(gè)字母采用小寫(xiě)。例如:

class AllTheColorsOfTheRainbow {
int anIntegerRepresentingColors;
void changeTheHueOfTheColor(int newHue) {
// ...
}
// ...
}

當然,要注意用戶(hù)也必須鍵入所有這些長(cháng)名字,而且不能輸錯。

2.10 總結
通過(guò)本章的學(xué)習,大家已接觸了足夠多的Java編程知識,已知道如何自行編寫(xiě)一個(gè)簡(jiǎn)單的程序。此外,對語(yǔ)言的總體情況以及一些基本思想也有了一定程度的認識。然而,本章所有例子的模式都是單線(xiàn)形式的“這樣做,再那樣做,然后再做另一些事情”。如果想讓程序作出一項選擇,又該如何設計呢?例如,“假如這樣做的結果是紅色,就那樣做;如果不是,就做另一些事情”。對于這種基本的編程方法,下一章會(huì )詳細說(shuō)明在Java里是如何實(shí)現的。

2.11 練習
(1) 參照本章的第一個(gè)例子,創(chuàng )建一個(gè)“Hello,World”程序,在屏幕上簡(jiǎn)單地顯示這句話(huà)。注意在自己的類(lèi)里只需一個(gè)方法(“main”方法會(huì )在程序啟動(dòng)時(shí)執行)。記住要把它設為static形式,并置入自變量列表——即使根本不會(huì )用到這個(gè)列表。用javac編譯這個(gè)程序,再用java運行它。
(2) 寫(xiě)一個(gè)程序,打印出從命令行獲取的三個(gè)自變量。
(3) 找出Property.java第二個(gè)版本的代碼,這是一個(gè)簡(jiǎn)單的注釋文檔示例。請對文件執行javadoc,并在自己的Web瀏覽器里觀(guān)看結果。
(4) 以練習(1)的程序為基礎,向其中加入注釋文檔。利用javadoc,將這個(gè)注釋文檔提取為一個(gè)HTML文件,并用Web瀏覽器觀(guān)看。

 

 

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
java中final的用法
Huihoo Power! - 對比C 和Java
使用 WSAD V5.1 中的 JAXB 來(lái)開(kāi)發(fā)企業(yè)應用程序(Custom Binding)
Java教程電子文檔下載
帶你快速看完9.8分神作《Effective Java》—— 方法篇
Java 基礎語(yǔ)法
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久