国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Thinking in Java | CHAPTER 2


第2章 一切都是對象

“盡管以C++為基礎(chǔ),但Java是一種更純粹的面向?qū)ο蟪绦蛟O(shè)計語言”。
無論C++還是Java都屬于雜合語言。但在Java中,設(shè)計者覺得這種雜合并不象在C++里那么重要。雜合語言允許采用多種編程風格;之所以說C++是一種雜合語言,是因為它支持與C語言的向后兼容能力。由于C++是C的一個超集,所以包含的許多特性都是后者不具備的,這些特性使C++在某些地方顯得過于復雜。
Java語言首先便假定了我們只希望進行面向?qū)ο蟮某绦蛟O(shè)計。也就是說,正式用它設(shè)計之前,必須先將自己的思想轉(zhuǎn)入一個面向?qū)ο蟮氖澜纾ǔ窃缫蚜晳T了這個世界的思維方式)。只有做好這個準備工作,與其他OOP語言相比,才能體會到Java的易學易用。在本章,我們將探討Java程序的基本組件,并體會為什么說Java乃至Java程序內(nèi)的一切都是對象。

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

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

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

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

主類型

大小

最小值

最大值

封裝器類型

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版沒有。

數(shù)值類型全都是有符號(正負號)的,所以不必費勁尋找沒有符號的類型。
主數(shù)據(jù)類型也擁有自己的“封裝器”(wrapper)類。這意味著假如想讓堆內(nèi)一個非主要對象表示那個主類型,就要使用對應(yīng)的封裝器。例如:
char c = ‘x‘;
Character C = new Character(‘c‘);
也可以直接使用:
Character C = new Character(‘x‘);
這樣做的原因?qū)⒃谝院蟮恼鹿?jié)里解釋。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

主類型 默認值

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

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

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

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

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

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

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

④:對于前面提及的“特殊”數(shù)據(jù)類型boolean,char,byte,short,int,long,,float以及double來說是一個例外。但在傳遞對象時,通常都是指傳遞指向?qū)ο蟮木浔?br>
下面讓我們考慮將一個字串作為自變量使用的方法。下面列出的是定義代碼,必須將它置于一個類定義里,否則無法編譯:

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

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

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

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

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

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

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

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

class StaticTest {
Static int i = 47;
}

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

2.7 我們的第一個Java程序
最后,讓我們正式編一個程序(注釋⑤)。它能打印出與當前運行的系統(tǒng)有關(guān)的資料,并利用了來自Java標準庫的System對象的多種方法。注意這里引入了一種額外的注釋樣式:“//”。它表示到本行結(jié)束前的所有內(nèi)容都是注釋:

// 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)境里,程序會在屏幕上一切而過,甚至沒機會看到結(jié)果??蓪⑾旅孢@段代碼置于main()的末尾,用它暫停輸出:
try {
Thread.currentThread().sleep(5 * 1000);
} catch(InterruptedException e) {}
}
它的作用是暫停輸出5秒鐘。這段代碼涉及的一些概念要到本書后面才會講到。所以目前不必深究,只知道它是讓程序暫停的一個技巧便可。


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

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

/* 這是
* 一段注釋,
* 它跨越了多個行
*/

但請記住,進行編譯時,/*和*/之間的所有東西都會被忽略,所以上述注釋與下面這段注釋并沒有什么不同:

/* 這是一段注釋,
它跨越了多個行 */

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

// 這是一條單行注釋


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

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

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

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

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

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

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

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

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

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

@see 類名
@see 完整類名
@see 完整類名#方法名

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

2.8.5 類文檔標記
隨同嵌入HTML和@see引用,類文檔還可以包括用于版本信息以及作者姓名的標記。類文檔亦可用于“接口”目的(本書后面會詳細解釋)。

1. @version
格式如下:
@version 版本信息
其中,“版本信息”代表任何適合作為版本說明的資料。若在javadoc命令行使用了“-version”標記,就會從生成的HTML文檔里提取出版本信息。

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

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

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

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

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

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

4. @deprecated
這是Java 1.1的新特性。該標記用于指出一些舊功能已由改進過的新功能取代。該標記的作用是建議用戶不必再使用一種特定的功能,因為未來改版時可能摒棄這一功能。若將一個方法標記為@deprecated,則使用該方法時會收到編譯器的警告。

2.8.8 文檔示例
下面還是我們的第一個Java程序,只不過已加入了完整的文檔注釋:

92頁程序

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

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

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

當然,要注意用戶也必須鍵入所有這些長名字,而且不能輸錯。

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

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

 

 

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

聯(lián)系客服