亚洲国产日韩一区二区,亚洲女同av,免费污视频在线http://www.aygfsteel.com/gufen/zh-cnSun, 06 Jul 2025 03:57:01 GMTSun, 06 Jul 2025 03:57:01 GMT60MyEclipse+WebSphere通過(guò)JNDI連接Sybase簡(jiǎn)介http://www.aygfsteel.com/gufen/archive/2006/06/12/52182.html落花飛雪落花飛雪Mon, 12 Jun 2006 04:57:00 GMThttp://www.aygfsteel.com/gufen/archive/2006/06/12/52182.htmlhttp://www.aygfsteel.com/gufen/comments/52182.htmlhttp://www.aygfsteel.com/gufen/archive/2006/06/12/52182.html#Feedback0http://www.aygfsteel.com/gufen/comments/commentRss/52182.htmlhttp://www.aygfsteel.com/gufen/services/trackbacks/52182.html閱讀全文

]]>
JDK5.0的11個(gè)主要新特征http://www.aygfsteel.com/gufen/archive/2005/10/15/15567.html落花飛雪落花飛雪Sat, 15 Oct 2005 04:15:00 GMThttp://www.aygfsteel.com/gufen/archive/2005/10/15/15567.htmlhttp://www.aygfsteel.com/gufen/comments/15567.htmlhttp://www.aygfsteel.com/gufen/archive/2005/10/15/15567.html#Feedback1http://www.aygfsteel.com/gufen/comments/commentRss/15567.htmlhttp://www.aygfsteel.com/gufen/services/trackbacks/15567.html閱讀全文

]]>
Win32下Swt-Designer4.1.1與MyEclipse4.0的破解方法及注冊(cè)機(jī)http://www.aygfsteel.com/gufen/archive/2005/09/27/14184.html落花飛雪落花飛雪Tue, 27 Sep 2005 05:05:00 GMThttp://www.aygfsteel.com/gufen/archive/2005/09/27/14184.htmlhttp://www.aygfsteel.com/gufen/comments/14184.htmlhttp://www.aygfsteel.com/gufen/archive/2005/09/27/14184.html#Feedback48http://www.aygfsteel.com/gufen/comments/commentRss/14184.htmlhttp://www.aygfsteel.com/gufen/services/trackbacks/14184.htmlWin32Swt-Designer4.1.1破解

環(huán)境:win32,Eclipse3.1,Designer_v4.1.1

1.  首先去http://www.swt-designer.com/左邊的download菜單點(diǎn)擊進(jìn)去后下載Edition for Eclipse 3.1 & 3.2,下載后的文件名為Designer_v4.1.1_for_Eclipse3.1.zipSnap2.gif

2.  然后在我的網(wǎng)絡(luò)硬盤中下載破解文件: http://www.thefilehut.com/userfiles/gufen/forblog/swt.designer.pro.keygen.for.eclipse.3.1.rar

3.  解壓后在cmd命令中敲入swt.ui.bat,運(yùn)行后出現(xiàn)以下界面,輸入框中的內(nèi)容,然后點(diǎn)擊Generate產(chǎn)生序列號(hào)和激活碼。

Snap3.gif
如果你所使用的環(huán)境和版本不是
win32,Eclipse3.1,Designer_v4.1.1,請(qǐng)參照http://blog.chinaz.com/u1/530/archives/2005/1789.shtml來(lái)進(jìn)行破解。這種情況下需要:

a) 將該目錄下的org.eclipse.swt.win32.win32.x86_3.1.0.jarswt-win32-3138.dll刪除

b)Eclipse目錄下找到swt.jar(名字視版本而定,eclipse3.1下是org.eclipse.swt.win32.win32.x86_3.1.0.jar swt-win32-2135.dll(名字視版本而定,eclipse3.1下是swt-win32-3138.dll2個(gè)文件,拷貝到swt.ui.bat所在的目錄。

c)修改swt.ui.bat,如這樣:

原來(lái)是: start javaw -cp SWTDesigner_2.0.0_Keygen.jar;org.eclipse.swt.win32.win32.x86_3.1.0.jar swtdesigner.keygen.SWTUI

修改為:start javaw -cp SWTDesigner_2.0.0_Keygen.jar;swt.jar swtdesigner.keygen.SWTUI

紅色為修改的地方,然后運(yùn)行后將Version填入你下載的swt-designer版本號(hào)即可產(chǎn)生注冊(cè)碼。

4.         將下載的Designer_v4.1.1_for_Eclipse3.1.zip插件安裝到eclipse,如果你不知道如何安裝插件請(qǐng)?jiān)?/SPAN>google里搜索這方面的文章,應(yīng)該很多的。我也是這樣走過(guò)來(lái)的。

運(yùn)行eclipse,打開(kāi)window->preferences…->選擇左邊樹形中的designer(如果沒(méi)有這一項(xiàng)說(shuō)明swt-designer插件沒(méi)有安裝成功)->點(diǎn)擊右下的“Registration and Activation->彈出“Product Registration and Activation”框,用默認(rèn)直接點(diǎn)擊Next->這一步需要注意的是Name框中兩個(gè)字符串之間要有個(gè)空格,他會(huì)認(rèn)為一個(gè)是姓一個(gè)是名,否則Next按鈕一直是灰的,其他隨便填,email框中要合乎email格式就可以了->輸入破解產(chǎn)生的序列號(hào)和激活碼->顯示“Activation is complete. Thank you.”表示破解成功

現(xiàn)在就可以免費(fèi)使用swt-designer

 

Win32MyEclipse4.0破解

這個(gè)破解起來(lái)很簡(jiǎn)單,先去http://www.myeclipseide.com下載Myeclipse4.0,然后去http://www.thefilehut.com/userfiles/gufen/forblog/MyEclipse-4.0.0-GA.Keygen.zip下載破解。安裝Myeclipse,之后解壓破解文件后運(yùn)行keygen.bat,產(chǎn)生一個(gè)key,之后在Myeclipse注冊(cè)一下就可以了。Myeclipse我忘記什么地方注冊(cè)了,好像裝好Myeclipse后在preferences中的Myeclipse里點(diǎn)幾下就會(huì)彈出來(lái)個(gè)框,把key copy過(guò)去確認(rèn)就可以了。

以上破解方法僅供個(gè)人學(xué)習(xí),請(qǐng)支持正版。(形式?)



]]>
軟件設(shè)計(jì)中的原則http://www.aygfsteel.com/gufen/archive/2005/09/26/14126.html落花飛雪落花飛雪Mon, 26 Sep 2005 09:21:00 GMThttp://www.aygfsteel.com/gufen/archive/2005/09/26/14126.htmlhttp://www.aygfsteel.com/gufen/comments/14126.htmlhttp://www.aygfsteel.com/gufen/archive/2005/09/26/14126.html#Feedback0http://www.aygfsteel.com/gufen/comments/commentRss/14126.htmlhttp://www.aygfsteel.com/gufen/services/trackbacks/14126.html     這里說(shuō)的幾個(gè)軟件模式是屬于原則層次一級(jí)的,比GoF等軟件設(shè)計(jì)模式高一層。遵循這些原則可以使我們?cè)O(shè)計(jì)出來(lái)的軟件有更好的可復(fù)用性和可維護(hù)性,同樣GoF等軟件設(shè)計(jì)模式也是遵循這一原則的。

     下邊的條列只是簡(jiǎn)單的介紹,以便忘記了偶爾過(guò)來(lái)游覽一下,詳細(xì)的介紹請(qǐng)參閱:《Java模式》、《UML和模式應(yīng)用-面向?qū)ο蠓治雠c設(shè)計(jì)導(dǎo)論》

1.         GRASP模式

GRASPGeneral Responsibility Assignment Software Pattern(通用指責(zé)分配軟件模式)的縮寫。

1)  專家模式(Expert)

解決方案:將職責(zé)分配給具有履行職責(zé)所需要的信息的類

通俗點(diǎn)就是:該干嘛干嘛去,別管別人的閑事或者我的職責(zé)就是搞這個(gè),別的事不管。

舉個(gè)簡(jiǎn)單的例子,如果有一個(gè)類是專門處理字符串相關(guān)的類,那么這個(gè)類只能有字符串處理相關(guān)的方法,而不要將日期處理的方法加進(jìn)來(lái)。也就是提高軟件高內(nèi)聚一種原則。

2)  創(chuàng)建者(Creator)

解決方案:將創(chuàng)建一個(gè)類A的實(shí)例的職責(zé)指派給類B的實(shí)例,如果下列條件滿足的話:

a)         B聚合了A對(duì)象

b)        B包含了A對(duì)象

c)        B紀(jì)錄了A對(duì)象的實(shí)例

d)        B要經(jīng)常使用A對(duì)象

e)         當(dāng)A的實(shí)例被創(chuàng)建時(shí),B具有要傳遞給A的初始化數(shù)據(jù)(也就是說(shuō)B是創(chuàng)建A的實(shí)例這項(xiàng)任務(wù)的信息專家)

f)         BA對(duì)象的創(chuàng)建者

如果以上條件中不止一條成立的話,那么最好讓B聚集或包含A

通俗點(diǎn)就是:我要用你所以我來(lái)創(chuàng)建你,請(qǐng)不要讓別人創(chuàng)建你

這個(gè)模式是支持低耦合度原則的一個(gè)體現(xiàn)

3)  高聚合度或高內(nèi)聚(High Cohesion)

解決方案:分配一個(gè)職責(zé)的時(shí)候要保持類的高聚合度

聚合度或內(nèi)聚度(cohesion)是一個(gè)類中的各個(gè)職責(zé)之間相關(guān)程度和集中程度的度量。一個(gè)具有高度相關(guān)職責(zé)的類并且這個(gè)類所能完成的工作量不是特別巨大,那么他就是具有高聚合度。

4)  低耦合度或低耦合(Low Coupling)

解決方案:在分配一個(gè)職責(zé)時(shí)要使保持低耦合度。

耦合度(coupling)是一個(gè)類與其它類關(guān)聯(lián)、知道其他類的信息或者依賴其他類的強(qiáng)弱程度的度量。一個(gè)具有低()耦合度的類不依賴于太多的其他類。

5)  控制者(Controller)

解決方案:將處理系統(tǒng)事件消息的職責(zé)分派給代表下列事物的類:

a)         代表整個(gè)“系統(tǒng)”的類(虛包控制者)

b)        代表整個(gè)企業(yè)或組織的類(虛包控制者)

c)        代表真實(shí)世界中參與職責(zé)(角色控制者)的主動(dòng)對(duì)象類(例,一個(gè)人的角色)

d)        代表一個(gè)用況中所有事件的人工處理者類,通常用“<用例名>處理者”的方式命名(用例控制者)

這是一個(gè)控制者角色職責(zé)分配的原則,就是哪些控制應(yīng)該分派給哪個(gè)角色。

6)多態(tài)

當(dāng)相關(guān)的可選擇的方法或行為隨著類型變化時(shí),將行為的職責(zé)-使用多態(tài)的操作-分配給那些行為變化的類型

也就是說(shuō)盡量對(duì)抽象層編程,用多態(tài)的方法來(lái)判斷具體應(yīng)該使用那個(gè)類,而不是用if instanceof 來(lái)判斷該類是什么接來(lái)執(zhí)行什么。

7)純虛構(gòu)

一個(gè)純虛構(gòu)意味著虛構(gòu)某些事物,而不是到了迫不得已我們才這樣做。

例,我們的Sale類的數(shù)據(jù)要存入數(shù)據(jù)庫(kù),但是他必須和數(shù)據(jù)庫(kù)接口相連接,如果將接口連接放入Sale類中勢(shì)必增加該類的耦合度,所以我們可以虛構(gòu)一個(gè)類來(lái)處理與數(shù)據(jù)庫(kù)接口連接的問(wèn)題。這個(gè)類就是我們虛構(gòu)出來(lái)的一個(gè)事物。

8)中介者

將職責(zé)分配給一個(gè)中間對(duì)象以便在其他構(gòu)件或服務(wù)之間仲裁,這樣這些構(gòu)件或服務(wù)沒(méi)有被直接耦合。這個(gè)中間對(duì)象(intermediary)在其他構(gòu)件或服務(wù)間創(chuàng)建一個(gè)中介者(Indirection)。這個(gè)中間對(duì)象也就事7)中的純虛構(gòu)。

9)不要和陌生人講話

分配職責(zé)給一個(gè)客戶端的直接對(duì)象以使它與一個(gè)間接對(duì)象進(jìn)行協(xié)作,這樣客戶端無(wú)需知道這個(gè)間接對(duì)象。

這個(gè)模式-也被叫做(Demeter)準(zhǔn)則。

       通俗點(diǎn)就是:只與你直接的朋友們通信

                            不要跟“陌生人”說(shuō)話

每個(gè)軟件單位對(duì)其他的單位都只有最少的知識(shí),而且局限于那些與本單位密切相關(guān)的軟件單位

2.         其他設(shè)計(jì)原則

1)“開(kāi)-閉”原則(Open-Closed Principle,或者OCP

一個(gè)軟件實(shí)體應(yīng)當(dāng)對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉。

意思就是在設(shè)計(jì)一個(gè)模塊的時(shí)候,應(yīng)當(dāng)使這個(gè)模塊在不被修改的前提下被擴(kuò)展。換言之,應(yīng)當(dāng)可以在不修改代碼的情況下改變這個(gè)模塊的行為。

2)里氏代換原則(Liskov Substitution Principle, 或者LSP

這個(gè)就是盡量用多態(tài)的方法編程,也就是GRASP模式中的多態(tài)。

3)依賴倒轉(zhuǎn)原則(Dependency Inversion Principle, 或者DIP

依賴倒轉(zhuǎn)原則講的是:要依賴于抽象,不要依賴于具體

就是說(shuō)我們盡量在抽象層進(jìn)行控制編程,要針對(duì)接口編程,不要針對(duì)實(shí)現(xiàn)編程。

4)接口隔離原則(Interface Segregation Principle, 或者ISP

使用多個(gè)專門的接口比使用單一的總接口要好。也就是,從一個(gè)客戶類的角度來(lái)講:一個(gè)類對(duì)另外一個(gè)類的依賴性應(yīng)當(dāng)是建立在最小的接口上的。

5)組合/聚合復(fù)用原則(Composition/Aggregation Principle, 或者CARP

又叫合成復(fù)用原則。原則就是在一個(gè)新的對(duì)象里面使用一些已有的對(duì)象,使之成為新對(duì)象的一部分:新的對(duì)象通過(guò)向這些對(duì)象的委派達(dá)到復(fù)用已有功能的目的。也就是,要盡量使用類的合成復(fù)用,盡量不要使用繼承

6)變與不變的分離
    更擴(kuò)展一步,就是將不同變化的組件進(jìn)行隔離.最簡(jiǎn)單的例子就是javabean中的存取器。它隔離了不變的接口和變化的內(nèi)部屬性。這方面體現(xiàn)最好的個(gè)人覺(jué)得就是eclipse,通過(guò)變化的插件,eclipse可以用來(lái)實(shí)現(xiàn)任何功能。



]]>
終于找到個(gè)適合自己的地方了。http://www.aygfsteel.com/gufen/archive/2005/09/25/13995.html落花飛雪落花飛雪Sun, 25 Sep 2005 07:31:00 GMThttp://www.aygfsteel.com/gufen/archive/2005/09/25/13995.htmlhttp://www.aygfsteel.com/gufen/comments/13995.htmlhttp://www.aygfsteel.com/gufen/archive/2005/09/25/13995.html#Feedback0http://www.aygfsteel.com/gufen/comments/commentRss/13995.htmlhttp://www.aygfsteel.com/gufen/services/trackbacks/13995.html

]]>
《JSP技術(shù)大全》筆記http://www.aygfsteel.com/gufen/archive/2005/09/25/13994.html落花飛雪落花飛雪Sun, 25 Sep 2005 07:25:00 GMThttp://www.aygfsteel.com/gufen/archive/2005/09/25/13994.htmlhttp://www.aygfsteel.com/gufen/comments/13994.htmlhttp://www.aygfsteel.com/gufen/archive/2005/09/25/13994.html#Feedback0http://www.aygfsteel.com/gufen/comments/commentRss/13994.htmlhttp://www.aygfsteel.com/gufen/services/trackbacks/13994.html1. 三個(gè)偽指令
1.1 <%@ page%>
語(yǔ)法: <%@ page attribute=”value” attribute=”value” … %>
屬性:
language=”java”,目前僅java
extends=”classeName”,指定當(dāng)前jsp應(yīng)該作為哪個(gè)超類的子類,一般不用設(shè)置
import=”importList”,引入jsp中要用到類
session=”true|false”,指定jsp頁(yè)面是否需要一個(gè)session,默認(rèn)true。一般不用設(shè)置
buffer=”none|size”,描述jsp采用的輸出緩存模型,默認(rèn)8k,一般不用設(shè)置。與aotoFlus和配合使用
aotoFlush=”true|false”
isThreadSafe=”true|false”,默認(rèn)true, 一般不用設(shè)置
info=”info_text”,jsp頁(yè)面的一些描述性信息,可以用servlet的getServletInfo()得到
contentType=”ctinfo”,請(qǐng)求應(yīng)用返回一個(gè)HTTP Content-Type頭標(biāo),一般為contentType=”type/subtype; charset=charset”,例如:<%@ page contentType=”text/html; charset=utf-8” %>
errorPage=”error_url”,指定如果該jsp頁(yè)面出錯(cuò)將顯示那個(gè)頁(yè)面
isErrorPage=”true|false”,如果為true則聲明了該頁(yè)面是其它jsp頁(yè)面出錯(cuò)后顯示的頁(yè)面
1.2 <%@ include%>
語(yǔ)法: <%@ include file=”filename” %>
說(shuō)明:filename必須是相對(duì)的URL文檔,即只能包含路徑信息,沒(méi)有協(xié)議或服務(wù)器信息。以“/”開(kāi)始,被認(rèn)為是相對(duì)servlet上下文根的絕對(duì)路徑。否則,文件名被認(rèn)為是相對(duì)于當(dāng)前JSP頁(yè)面的。
在JSP被容器轉(zhuǎn)換成servlet前首先將filename中的文本復(fù)制到相應(yīng)位置,然后再轉(zhuǎn)換為servlet。如果當(dāng)前JSP頁(yè)面中存在多個(gè)<%@ include%>偽指令,則根據(jù)出現(xiàn)的前后順序依次復(fù)制過(guò)來(lái)。
1.3 <%@ taglib%>
語(yǔ)法:<%@ taglib url=”tagLIbraryURL” prefix=”tagPrefix” %>
啟用已經(jīng)定義過(guò)的一個(gè)標(biāo)簽庫(kù)
tagLIbraryURL:標(biāo)簽庫(kù)描述器的url
tagPrefix:用于標(biāo)識(shí)在頁(yè)面后面部分使用定制標(biāo)簽的唯一前綴
例如:如果abc.tld定義了一個(gè)名為table的標(biāo)簽,那么我們可以
<%@ taglib url=”/tlds/abc.tld” prefix=”ft” %>
然后就可以用該標(biāo)簽<ft:table> …</ft:table>
2. 兩種注釋
<%-- 僅jsp可見(jiàn) --%>
<!-- html中也可見(jiàn) -->
3. 表達(dá)式
<%= exp%>
4. scriptliet: 多個(gè)jsp語(yǔ)句的集合
<% statement;[statement;…]%>
scriptliet在servlet中的service() 方法中
5. 聲明
<%! statement;[statement;…]%>
聲明在servlet中的service() 方法之外,注意與scriptliet區(qū)別
6. 隱含變量
request(常用)
response(常用)
pageContext
session(常用)
application
out(常用)
config
page
exception
7. 標(biāo)準(zhǔn)行為
7.1. 概念
行為是創(chuàng)建、修改或使用對(duì)象的高層jsp元素。行為遵守嚴(yán)格的xml語(yǔ)法:
<tagname [attr=”value” attr=”value”…]>…</tagname>
如果沒(méi)有行為主體可簡(jiǎn)化為:<tagname [attr=”value” attr=”value”…] / >
7.2. 7種標(biāo)準(zhǔn)行為標(biāo)簽
<jsp:useBean>…< /jsp:useBean >
<jsp:setProperty … />
<jsp:getProperty … />
<jsp:include >…</jsp: include >
 語(yǔ)法:<jsp:include page=”resourcename” flush=”true” />
 說(shuō)明: resourcename 路徑規(guī)則同<%@ include%>
 表達(dá)式語(yǔ)法:<jsp:include page=”<%= jspfile %>” flush=”true” />
 向被調(diào)用的jsp頁(yè)面?zhèn)鬟f參數(shù):
<jsp:include page=”pageName” flush=”true”>
<jsp:parm name=”parm1Name” value=”parm1Value” />
<jsp:parm name=”parm2Name” value=”parm2Value” />
</jsp:include>
<jsp:forward>…</jsp: forward >
<jsp:param>…</jsp: param >
<jsp:plugin>…</jsp: plugin >
7.3. <jsp:include >…</jsp: include >與<%@ include%>的區(qū)別
<%@ include%>偽指令:用于在JSP源碼被轉(zhuǎn)換成JavaServlet源碼和被編譯前將靜態(tài)文本復(fù)制到其中。也就是在JSP中出現(xiàn)<%@ include%>的地方將<%@ include%>所包含的文件內(nèi)容直接拷貝到此處,以此實(shí)現(xiàn)將變化和不變化的代碼分離。典型情況下,文本為HTML代碼,但它可以是在JSP頁(yè)面內(nèi)顯示的任何內(nèi)容。
<jsp:include … />行為:使得servlet引擎調(diào)用另一URL,生成帶有最初JSP頁(yè)面的輸出。
在構(gòu)建一種思維模式的關(guān)鍵一點(diǎn)是<%@ include%>偽指令在編譯時(shí)只執(zhí)行一次,而<jsp:include >行為每次進(jìn)行請(qǐng)求時(shí)都執(zhí)行。<jsp:include >行為更像一個(gè)C語(yǔ)言的函數(shù)調(diào)用,因?yàn)樵赥omcat編譯后的源碼中可以看見(jiàn)將<jsp:include >翻譯為:pageContext.include(“resourcename”)。
此外還必須注意包含與被包含文件之間命名的沖突問(wèn)題。
8. 標(biāo)簽擴(kuò)展
除了以上7種標(biāo)準(zhǔn)行為的基本標(biāo)簽外,可以自由的擴(kuò)展標(biāo)簽
步驟:1)定義標(biāo)簽
   2)編寫標(biāo)簽庫(kù)描述器的接口(創(chuàng)建TLD入口)
   3)編寫標(biāo)簽處理器
    4)在JSP頁(yè)面中使用標(biāo)簽
9. JSP與XML
9.1. DTD(文檔類型定義,Document Type Definition): 用來(lái)定義XML元素及其規(guī)則
9.2. XML解析器
1) DOM(Document Object Module) 文檔對(duì)象模型
2) SAX(Simple API for XML) XML的簡(jiǎn)單API
SAX 較 DOM有很多優(yōu)點(diǎn)
可以使用XSLT處理器和XSL樣式單轉(zhuǎn)換XML


]]>
《Effective Java》筆記(選擇自 njchenyi 的 Blog)http://www.aygfsteel.com/gufen/archive/2005/09/25/13993.html落花飛雪落花飛雪Sun, 25 Sep 2005 07:24:00 GMThttp://www.aygfsteel.com/gufen/archive/2005/09/25/13993.htmlhttp://www.aygfsteel.com/gufen/comments/13993.htmlhttp://www.aygfsteel.com/gufen/archive/2005/09/25/13993.html#Feedback0http://www.aygfsteel.com/gufen/comments/commentRss/13993.htmlhttp://www.aygfsteel.com/gufen/services/trackbacks/13993.html有別人寫好的筆記,不用自己費(fèi)神寫了。對(duì)于看過(guò)Effective Java的偶而忘記某個(gè)條目,看看筆記或許能記起來(lái)。
 
Creating and Destroying Object
Item 1:考慮用靜態(tài)工廠方法替代構(gòu)造器
例如:public static Boolean valueOf(boolean b)
     {
          return (b?Boolean.TRUE:Boolean.FALSE);
     }
這樣的好處是方法有名字,并且它可以復(fù)用對(duì)象,不像構(gòu)造器每次調(diào)用都產(chǎn)生新的對(duì)象。其次它還可以返回返回類型的子類。不好的地方是如果沒(méi)有public or protected構(gòu)造器的類將不能被繼承。還有就是靜態(tài)工廠方法的名字和其他的靜態(tài)方法名字不容易區(qū)分。
Item 2:通過(guò)添加私有構(gòu)造器來(lái)加強(qiáng)單例屬性(singletom property)
例如:public class Hello
            {
                  private static final Hello Instance = new Hell();
                  private Hello()
                  {}
                   
                    public static Hello getInstance()
                      {
                     return Instance;
                     }
            }
這個(gè)私有構(gòu)造器只能在內(nèi)部被使用,確保了單例模式!
Item 3:避免創(chuàng)建重復(fù)的對(duì)象
對(duì)不可修改的對(duì)象盡量進(jìn)行復(fù)用,這樣效率和性能都會(huì)提高。例如如果循環(huán)100次String s = new String("hello")將創(chuàng)建100個(gè)對(duì)象 循環(huán)100次String s = "hello";則只創(chuàng)建了一個(gè)對(duì)象。很好的進(jìn)行了復(fù)用。
Item 4:用私有構(gòu)造器來(lái)避免被實(shí)例化
例如public UtilityClass
{
   private UtilityClass()
   {}
///
}
通常那些工具類是這么設(shè)計(jì)的
Item 5:消除絕對(duì)的對(duì)象引用
     雖然java中使用gc來(lái)管理內(nèi)存,但是如果不注意的話也會(huì)產(chǎn)生“內(nèi)存泄漏”。例如下面的程序
public class Stack
{
 private Object[] elements;
 private int size = 0;
 
 public Stack(int i)
 {
  this.elements = new Object[i];
 }
 
 public void push(Object e)
 {
  ensure();
  elements[size++] = e;
 }
 
 public Object pop()
 {
  if(size == 0)
  {
   ////
  }
 
  return elements[size--];
 }
 
 private void ensure()
 {
  ////
 }
}
標(biāo)記的地方存在著內(nèi)存泄漏的問(wèn)題,因?yàn)楫?dāng)他被彈出棧的時(shí)候,它也沒(méi)有成為可回收的垃圾對(duì)象,Stack維護(hù)著他們的絕對(duì)的引用。將不能更改。改進(jìn)的方法是如下的寫法
 public Object pop()
 {
  if(size == 0)
  {
   ////
  }
  Object obj = elements[--size];
  elements[size] = null;
 
  return obj;
 }
 但是切忌不要濫用null。
Item 6:避免finalizer
垃圾回收器是低線程級(jí)別運(yùn)行的且不能被強(qiáng)迫執(zhí)行。System.gc()只是建議垃圾回收器收集垃圾,它可不一定馬上運(yùn)行,而且垃圾回收器運(yùn)行的時(shí)候會(huì)掛起其他線程導(dǎo)致程序停止響應(yīng)。推薦使用的方法類似于
InputStream is = null;
try
{
      is = /////;
}
finally
{
      is.close();
}
Methods Common to All Objects
item 7:當(dāng)你覆蓋equals方法的時(shí)候一定要遵守general contact
   覆蓋equals的時(shí)候一定要加倍的小心,其實(shí)最好的辦法就是不覆蓋這個(gè)方法。比如在下面的情況下就可以不覆蓋
   1這個(gè)類的每個(gè)實(shí)例都是唯一的,例如Thread類
   2 如果你不關(guān)心這個(gè)類是否該提供一個(gè)測(cè)試邏輯相等的方法
   3超類已經(jīng)覆蓋了equals方法,并且它合適子類使用
   4如果這個(gè)類是private或者是package-private的,并且你確信他不會(huì)被調(diào)用
   但是當(dāng)我們要為這個(gè)類提供區(qū)分邏輯相等和引用相等的方法的時(shí)候,我們就必須要覆蓋這個(gè)方法了。例如String類,Date類等,覆蓋的時(shí)候我們一定要遵從general contact,說(shuō)白了就是一個(gè)合同。合同的主要內(nèi)容是
   1.x.equals(x)必須返回true
   2.x.equals(y)當(dāng)且僅當(dāng)y.equals(x)返回true的時(shí)候返回true
   3.x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)必須返回true
   4.如果沒(méi)有任何修改得話 那么多次調(diào)用x.equals(y)的返回值應(yīng)該不變
   5.任何時(shí)候非空的對(duì)象x,x.equals(null)必須返回false
下面是作者的建議如何正確的覆蓋equals方法
1.  用==檢查是否參數(shù)就是這個(gè)對(duì)象的引用
2.  用instanceof判斷參數(shù)的類型是否正確
3.  把參數(shù)轉(zhuǎn)換成合適的類型
4.  比較類的字段是不是匹配
例如:
public boolean equals(Object o)
{
       if(o== this) return true;
       if(!(o instanceof xxxx) return false;
       xxx in = (xxx)o;
       return ……..
}
最后一點(diǎn)要注意的時(shí)候不要提供這樣的方法public boolean equals(MyClass o)這樣是重載并不是覆蓋Object的equals方法
item 8 :當(dāng)你覆蓋equals的時(shí)候必須覆蓋hashCode方法
    這點(diǎn)必須切忌,不然在你和hash-based集合打交道的時(shí)候,錯(cuò)誤就會(huì)出現(xiàn)了。關(guān)鍵問(wèn)題在于一定要滿足相等的對(duì)象必須要有相等的hashCode。如果你在PhoneNumber類中覆蓋了equals方法,但是沒(méi)有覆蓋hashCode方法,那么當(dāng)你做如下操作的時(shí)候就會(huì)出現(xiàn)問(wèn)題了。
Map m = new HashMap();
m.put(new PhoneNumber(408,863,3334),”ming”)
當(dāng)你調(diào)用m.get(new PhoneNumber(408,863,3334))的時(shí)候你希望得到ming但是你卻得到了null,為什么呢因?yàn)樵谡麄€(gè)過(guò)程中有兩個(gè)PhoneNumber的實(shí)例,一個(gè)是put一個(gè)是get,但是他們兩個(gè)邏輯相等的實(shí)例卻得到不同的hashCode那么怎么可以取得以前存入的ming呢。
 
Item 9:永遠(yuǎn)覆蓋toString方法
    在Object的toString方法返回的形式是Class的類型加上@加上16進(jìn)制的hashcode。你最好在自己的類中提供toString方法更好的表述實(shí)例的信息,不然別人怎么看得明白呢。
Item 10:覆蓋clone()方法的時(shí)候一定要小心
    一個(gè)對(duì)象要想被Clone,那么要實(shí)現(xiàn)Clone()接口,這個(gè)接口沒(méi)有定義任何的方法,但是如果你不實(shí)現(xiàn)這個(gè)接口的話,調(diào)用clone方法的時(shí)候會(huì)出現(xiàn)CloneNotSupportedException,這就是作者叫做mixin的接口類型。通常clone()方法可以這樣覆蓋
public Object clone()
{
try
{
              return super.clone();
}
catch(CloneNotSupportedException e)
{}
}
但是當(dāng)你要clone的類里面含有可修改的引用字段的時(shí)候,那么你一定要把整個(gè)類的藍(lán)圖進(jìn)行復(fù)制,如果對(duì)你clone得到的對(duì)象進(jìn)行修改的時(shí)候還會(huì)影響到原來(lái)的實(shí)例,那么這是不可取的。所以應(yīng)該這樣clone()
public Object clone() throws CloneNotSupportedException
{
       Stack Result  = (Stack)super.clone();
       Result.elements = (Object[])elements.clone();
       Return result;
}
其中elements是stack類中可修改的引用字段,注意如果elements是final的話我們就無(wú)能為力了,因?yàn)椴荒芙o他重新賦值了.其實(shí)如果不是必須的話,根本就不用它最好。
 
Item 11:考慮適當(dāng)?shù)臅r(shí)候覆蓋Comparable接口
     Thinking in java上說(shuō)的更清楚,這里不多少了。
    越來(lái)越發(fā)現(xiàn)這是一本難得的好書,Java程序員不看這本書的話真是很遺憾。本章講述的是類和接口相關(guān)的問(wèn)題。這幾個(gè)Item都非常重要.
Item 12:把類和成員的可訪問(wèn)范圍降到最低
    好的模塊設(shè)計(jì)應(yīng)該盡最大可能封裝好自己的內(nèi)部信息,這樣可以把模塊之間的耦合程度降到最低。開(kāi)發(fā)得以并行,無(wú)疑這將加快開(kāi)發(fā)的速度,便于系統(tǒng)地維護(hù)。Java中通過(guò)訪問(wèn)控制符來(lái)解決這個(gè)問(wèn)題。
public表示這個(gè)類在任何范圍都可用。
protected表示只有子類和包內(nèi)的類可以使用
private-package(default)表示在包內(nèi)可用
private表示只有類內(nèi)才可以用
你在設(shè)計(jì)一個(gè)類的時(shí)候應(yīng)該盡量的按照4321得順序設(shè)計(jì)。如果一個(gè)類只是被另一個(gè)類使用,那么應(yīng)該考慮把它設(shè)計(jì)成這個(gè)類的內(nèi)部類。通常public的類不應(yīng)該有public得字段,不過(guò)我們通常會(huì)用一個(gè)類來(lái)定義所有的常量,這是允許的。不過(guò)必須保證這些字段要么是基本數(shù)據(jù)類型要么引用指向的對(duì)象是不可修改的。不然他們將可能被修改。例如下面的定義中data就是不合理的,后面兩個(gè)沒(méi)有問(wèn)題。
public class Con
{
      public static final int[] data = {1,2,3};// it is bad
      public static final String hello = "world";
      public static final int i = 1;
}
Item 13:不可修改的類更受青睞
    不可修改的類意思是他們一經(jīng)創(chuàng)建就不會(huì)改變,例如String類。他們的設(shè)計(jì)、實(shí)現(xiàn)都很方便,安全性高——它們是線程安全的。設(shè)計(jì)不可修改類有幾點(diǎn)規(guī)則:
不要提供任何可以修改對(duì)象的方法
確保沒(méi)有方法能夠被覆蓋,可以通過(guò)把它聲明為final
所有字段設(shè)計(jì)成final
所有字段設(shè)計(jì)成private
確保外部不能訪問(wèn)到類的可修改的組件
不可修改類也有個(gè)缺點(diǎn)就是創(chuàng)建不同值得類的時(shí)候要?jiǎng)?chuàng)建不同的對(duì)象,String就是這樣的。通常有個(gè)解決的辦法就是提供一個(gè)幫助類來(lái)彌補(bǔ),例如StringBuffer類。
Item 14:化合(合成)比繼承更值得考慮
      實(shí)現(xiàn)代碼重用最重要的辦法就是繼承,但是繼承破壞了封裝,導(dǎo)致軟件的鍵壯性不足。如果子類繼承了父類,那么它從父類繼承的方法就依賴父類的實(shí)現(xiàn),一旦他改變了會(huì)導(dǎo)致不可預(yù)測(cè)的結(jié)果。作者介紹了InstrumentedHashSet作為反例進(jìn)行說(shuō)明,原因就是沒(méi)有明白父類的方法實(shí)現(xiàn)。作者給出的解決辦法是通過(guò)化合來(lái)代替繼承,用包裝類和轉(zhuǎn)發(fā)方法來(lái)解決問(wèn)題。把想擴(kuò)展的類作為本類的一個(gè)private final得成員變量。把方法參數(shù)傳遞給這個(gè)成員變量并得到返回值。這樣做的缺點(diǎn)是這樣的類不適合回掉框架。繼承雖然好,我們卻不應(yīng)該濫用,只有我們能確定它們之間是is-a得關(guān)系的時(shí)候才使用。
Item 15:如果要用繼承那么設(shè)計(jì)以及文檔都要有質(zhì)量保證,否則就不要用它
    為了避免繼承帶來(lái)的問(wèn)題,你必須提供精確的文檔來(lái)說(shuō)明覆蓋相關(guān)方法可能出現(xiàn)的問(wèn)題。在構(gòu)造器內(nèi)千萬(wàn)不要調(diào)用可以被覆蓋的方法,因?yàn)樽宇惛采w方法的時(shí)候會(huì)出現(xiàn)問(wèn)題。
import java.util.*;
public class SubClass extends SuperClass
{
 private final Date date;
 
 public SubClass()
 {
  date = new Date();
 }
 
 public void m()
 {
  System.out.println(date);
 }
 
 public static void main(String[] args)
 {
  SubClass s = new SubClass();
  s.m();
 }
 
}
class SuperClass
{
 public SuperClass()
 {
  m();
 }
 
 public void m()
 {
 
 }
}
由于在date被初始化之前super()已經(jīng)被調(diào)用了,所以第一次輸出null而不是當(dāng)前的時(shí)間。
由于在Clone()或者序列化的時(shí)候非常類似構(gòu)造器的功能,因此readObject()和clone()方法內(nèi)最好也不要包括能被覆蓋的方法。
Item 16:在接口和抽象類之間優(yōu)先選擇前者
      接口和抽象類都用來(lái)實(shí)現(xiàn)多態(tài),不過(guò)我們應(yīng)該優(yōu)先考慮用接口。知道嗎?James說(shuō)過(guò)如果要讓他重新設(shè)計(jì)java的話他會(huì)把所有都設(shè)計(jì)成接口的。抽象類的優(yōu)點(diǎn)是方便擴(kuò)展,因?yàn)樗潜焕^承的,并且方法可以在抽象類內(nèi)實(shí)現(xiàn),接口則不行。
Item 17:接口只應(yīng)該用來(lái)定義類型
      接口可以這樣用的 Collection c = new xxxx();這是我們最常用的。不要把接口用來(lái)做其他的事情,比如常量的定義。你應(yīng)該定義一個(gè)類,里面包含public final static 得字段。
Item 18: 在靜態(tài)和非靜態(tài)內(nèi)部類之間選擇前者
      如果一個(gè)類被定義在其他的類內(nèi)部那么它就是嵌套類,可以分為靜態(tài)內(nèi)部類、非靜態(tài)內(nèi)部類和匿名類。
   static member class 得目的是為enclosing class服務(wù),如果還有其他的目的,就應(yīng)該把它設(shè)計(jì)成top-level class。nonstatic member class是和enclosing class instance關(guān)聯(lián)的,如果不需要訪問(wèn)enclosing class instance的話應(yīng)該把它設(shè)計(jì)成static得,不然會(huì)浪費(fèi)時(shí)間和空間。anonymous class是聲明和初始化同時(shí)進(jìn)行的??梢苑旁诖a的任意位置。典型應(yīng)用是Listener 和process object例如Thread。
    由于以前學(xué)過(guò)C語(yǔ)言,所以對(duì)C還是蠻有感情,而JAVA和C又有很多相似之處,很多從C轉(zhuǎn)過(guò)來(lái)學(xué)習(xí)JAVA的兄弟,可能一開(kāi)始都不是很適應(yīng),因?yàn)楹芏嘣贑里面的結(jié)構(gòu)在JAVA里面都不能使用了,所以下面我們來(lái)介紹一下C語(yǔ)言結(jié)構(gòu)的替代。
      Item 19:用類代替結(jié)構(gòu)
     JAVA剛面世的時(shí)候,很多C程序員都認(rèn)為用類來(lái)代替結(jié)構(gòu)現(xiàn)在太復(fù)雜,代價(jià)太大了,但是實(shí)際上,如果一個(gè)JAVA的類退化到只包含一個(gè)數(shù)據(jù)域的話,這樣的類與C語(yǔ)言的結(jié)構(gòu)大致是等價(jià)的。
      比方說(shuō)下面兩個(gè)程序片段:
      class Point
      {
       private float x;
       private float y;
      }
      實(shí)際上這段代碼和C語(yǔ)言的結(jié)構(gòu)基本上沒(méi)什么區(qū)別,但是這段代碼恐怕是眾多OO設(shè)計(jì)Fans所不齒的,因?yàn)樗鼪](méi)有體現(xiàn)封裝的優(yōu)異性,沒(méi)有體現(xiàn)面向?qū)ο笤O(shè)計(jì)的優(yōu)點(diǎn),當(dāng)一個(gè)域被修改的時(shí)候,你不可能再采取任何輔助的措施了,那我們?cè)賮?lái)看一看采用包含私有域和共有訪問(wèn)方法的OO設(shè)計(jì)代碼段:
     class Point
      {
       private float x;
       private float y;
       public Point(float x,float y)
       {
             this.x=x;
             this.y=y;
       }
        public float getX(){retrun x;}
        public float getY(){return y;}
        public void setX(float x){this.x=x;}
        public void setY(float y){this.y=y;}
      }
        單從表面上看,這段代碼比上面那個(gè)多了很多行,還多了很多函數(shù),但是仔細(xì)想一下,這樣的OO設(shè)計(jì),似乎更人性化,我們可以方面的對(duì)值域進(jìn)行提取,修改等操作,而不直接和值域發(fā)生關(guān)系,這樣的代碼不僅讓人容易讀懂,而且很安全,還吸取了面向?qū)ο蟪绦蛟O(shè)計(jì)的靈活性,試想一下,如果一個(gè)共有類暴露它的值域,那么想要在將來(lái)的版本中進(jìn)行修改是impossible的,因?yàn)楣灿蓄惖目蛻舸a已經(jīng)遍布各處了。
需要提醒一點(diǎn)的是,如果一個(gè)類是包級(jí)私有的,或者是一個(gè)私有的嵌套類,則直接暴露其值域并無(wú)不妥之處。
Item 20:用類層次來(lái)代替聯(lián)合
我們?cè)谟肅語(yǔ)言來(lái)進(jìn)行開(kāi)發(fā)的時(shí)候,經(jīng)常會(huì)用到聯(lián)合這個(gè)概念,比如:
       typedef struct{
     double length;
     double width;    
}rectangleDimensions_t;
那我們?cè)贘AVA里面沒(méi)有聯(lián)合這個(gè)概念,那我們用什么呢?對(duì)!用繼承,這也是JAVA最吸引我的地方之一,它可以使用更好的機(jī)制來(lái)定義耽擱數(shù)據(jù)類型,在Bruce Eckel的Thinking in java里面也多次提到了一個(gè)和形狀有關(guān)的例子,我們可以先籠統(tǒng)的定義一個(gè)抽象類,即我們通常所指的超類,每個(gè)操作定義一個(gè)抽象的方法,其行為取決于標(biāo)簽的值,如果還有其他的操作不依賴于標(biāo)簽的值,則把操作變成根類(繼承的類)中的具體方法。
這樣做的最重要的優(yōu)點(diǎn)是:類層次提供了類型的安全性。
其次代碼非常明了,這也是OO設(shè)計(jì)的優(yōu)點(diǎn)。
而且它很容易擴(kuò)展,即使是面向多個(gè)方面的工作,能夠同樣勝任。
最后它可以反映這些類型之間本質(zhì)上的層次關(guān)系,從而允許更強(qiáng)的靈活性,以便編譯時(shí)類型檢查。
Item 21:用類來(lái)代替enum結(jié)構(gòu)
Java程序設(shè)計(jì)語(yǔ)言提出了類型安全枚舉的模式來(lái)替代enum結(jié)構(gòu),它的基本思想很簡(jiǎn)單:定義一個(gè)類來(lái)代表枚舉類型的單個(gè)元素,并且不提供任何公有的構(gòu)造函數(shù),相反,提供公有靜態(tài)final類,使枚舉類型中的每一個(gè)常量都對(duì)應(yīng)一個(gè)域。
類型安全枚舉類型的一個(gè)缺點(diǎn)是,裝載枚舉類的和構(gòu)造常量對(duì)象時(shí),需要一定的時(shí)間和空間開(kāi)銷,除非是在資源很受限制的設(shè)備比如蜂窩電哈和烤面包機(jī)上,否則在實(shí)際中這個(gè)問(wèn)題不會(huì)被考慮。
 總之,類型安全枚舉類型明顯優(yōu)于int類型,除非實(shí)在一個(gè)枚舉類型主要被用做一個(gè)集合元素,或者主要用在一個(gè)資源非常不受限的環(huán)境下,否則類型安全枚舉類型的缺點(diǎn)都不成問(wèn)題,依次,在要求使用一個(gè)枚舉類型的環(huán)境下,我們首先應(yīng)考慮類型安全枚舉類型模式。
Item 22:用類和接口來(lái)代替函數(shù)指針
眾所周知,JAVA語(yǔ)言和C的最大區(qū)別在于,前者去掉了指針,小生第一次接觸JAVA的時(shí)候覺(jué)得好不習(xí)慣,因?yàn)橥蝗灰幌伦記](méi)了指針,覺(jué)得好不方面啊,C語(yǔ)言的精髓在于其指針的運(yùn)用,而JAVA卻把它砍掉了,讓人好生郁悶,不過(guò)隨著時(shí)間的推移,我漸漸明白了用類和接口的應(yīng)用也同樣可以提供同樣的功能,我們可以直接定義一個(gè)這樣一個(gè)類,他的方法是執(zhí)行其他方法上的操作,如果一個(gè)類僅僅是導(dǎo)出這樣一個(gè)方法,那么它實(shí)際上就是一個(gè)指向該方法的指針,舉個(gè)例子:
class StringLengthComprator{
public int compare(String s1,String s2)
{
return s1.length()-s2.length();
}
}
這個(gè)類導(dǎo)出一個(gè)帶兩個(gè)字符串的方法,它是一個(gè)用于字符串比較的具體策略。它是無(wú)狀態(tài)的,沒(méi)有域,所以,這個(gè)類的所有實(shí)例在功能上都是等價(jià)的,可以節(jié)省不必要的對(duì)象創(chuàng)建開(kāi)銷。但是我們不好直接把這個(gè)類傳遞給可戶使用,因?yàn)榭蓱魺o(wú)法傳遞任何其他的比較策略。相反,我們可以定義一個(gè)接口,即我們?cè)谠O(shè)計(jì)具體策略類的時(shí)候還需要定義一個(gè)策略接口:
      public interface Comparator{
           public int compare(Object o1,Object o2);
}
  我們完全可以依照自己的需要來(lái)定義它。
具體的策略類往往使用匿名類聲明。
在JAVA中,我們?yōu)榱藢?shí)現(xiàn)指針的模式,聲明一個(gè)接口來(lái)表示該策略,并且為每個(gè)具體策略聲明一個(gè)實(shí)現(xiàn)了該接口的類,如果一個(gè)具體策略只被使用一次的話,那么通常使用匿名類來(lái)聲明和實(shí)例化這個(gè)具體策略類,如果一個(gè)策略類反復(fù)使用,那么它的類通常是一個(gè)私有的的靜態(tài)成員類。
下面我們來(lái)討論一下有關(guān)方法設(shè)計(jì)的幾個(gè)方面,下面說(shuō)的幾個(gè)要點(diǎn)大多數(shù)都是應(yīng)用在構(gòu)造函數(shù)中,當(dāng)然也使用于普通方法,我們追求的依然是程序的可用性,健壯性和靈活性。
Item 23:檢查參數(shù)的有效性
非公有的方法我們應(yīng)該用斷言的方法來(lái)檢查它的參數(shù),而不是使用通常大家所熟悉的檢查語(yǔ)句來(lái)檢測(cè)。如果我們使用的開(kāi)發(fā)平臺(tái)是JDK1.4或者更高級(jí)的平臺(tái),我們可以使用assert結(jié)構(gòu);否則我們應(yīng)該使用一種臨時(shí)的斷言機(jī)制。
有些參數(shù)在使用過(guò)程中是先保存起來(lái),然后在使用的時(shí)候再進(jìn)行調(diào)用,構(gòu)造函數(shù)正是這種類型的一種體現(xiàn),所以我們通常對(duì)構(gòu)造函數(shù)參數(shù)的有效性檢查是非常仔細(xì)的。
Item 24:需要時(shí)使用保護(hù)性拷貝
眾所周知,JAVA在代碼安全性方面較C/C++有顯著的提高,緩沖區(qū)溢出,數(shù)組越界,非法指針等等,我們的JAVA都有一個(gè)很完善的機(jī)制來(lái)進(jìn)行免疫,但是這并不代表我們不必去考慮JAVA的安全性,即便在安全的語(yǔ)言,如果不采取措施,還是無(wú)法使自己與其他類隔開(kāi)。假設(shè)類的客戶會(huì)盡一切手段來(lái)破壞這個(gè)類的約束條件,在這樣的前提下,你必須從保護(hù)性的方面來(lái)考慮設(shè)計(jì)程序。通過(guò)大量的程序代碼研究我們得出這樣的結(jié)論:對(duì)于構(gòu)造性函數(shù)的每個(gè)可變參數(shù)進(jìn)行保護(hù)性拷貝是必要的。需要注意的是,保護(hù)性拷貝是在檢查參數(shù)的有效性之前 進(jìn)行的,并且有效性檢查是針對(duì)拷貝之后的對(duì)象,而不是原始的對(duì)象。對(duì)于“參數(shù)類型可以被不可信方子類化”的情況,不要用clone方法來(lái)進(jìn)行參數(shù)的保護(hù)性拷貝。
對(duì)于參數(shù)的保護(hù)性拷貝并不僅僅在于非可變類,當(dāng)我們編寫一個(gè)函數(shù)或者一個(gè)構(gòu)造函數(shù)的時(shí)候,如果它要接受客戶提供的對(duì)象,允許該對(duì)象進(jìn)入到內(nèi)部數(shù)據(jù)結(jié)構(gòu)中,則有必要考慮一下,客戶提供的對(duì)象是否是可變的,如果是,則要考慮其變化的范圍是否在你的程序所能容納的范圍內(nèi),如果不是,則要對(duì)對(duì)象進(jìn)行保護(hù)性拷貝,并且讓拷貝之后的對(duì)象而不是原始對(duì)象進(jìn)入到數(shù)據(jù)結(jié)構(gòu)中去。當(dāng)然最好的解決方法是使用非可變的對(duì)象作為你的對(duì)象內(nèi)部足見(jiàn),這樣你就可以不必關(guān)心保護(hù)性拷貝問(wèn)題了。):
Item 25:謹(jǐn)慎使用設(shè)計(jì)方法的原型
(1)謹(jǐn)慎的選擇方法的名字:即要注意首先要是易于理解的,其次還要與該包中的其他方法的命名風(fēng)格相一致,最后當(dāng)然要注意取一個(gè)大眾所認(rèn)可的名字。
(2)不要追求提供便利的方法:每一個(gè)方法都應(yīng)該提供其應(yīng)具備的功能點(diǎn),對(duì)于接口和類來(lái)方法不要過(guò)多,否則會(huì)對(duì)學(xué)習(xí)使用維護(hù)等等方面帶來(lái)許多不必要的麻煩,對(duì)于每一個(gè)類型所支持的每一個(gè)動(dòng)作,都提供一個(gè)功能完全的方法,只有一個(gè)方法過(guò)于頻繁的使用時(shí),才考慮為它提供一個(gè)快捷方法。
(3)避免過(guò)長(zhǎng)的參數(shù)列表:通常在實(shí)踐中,我們以三個(gè)參數(shù)作為最大值,參數(shù)越少越好,類型相同的長(zhǎng)參數(shù)列尤其影響客戶的使用,兩個(gè)方法可以避免過(guò)長(zhǎng)的參數(shù)這樣的情況發(fā)生,一是把一個(gè)方法分解成多個(gè),每一個(gè)方法只要求使用這些參數(shù)的一個(gè)子集;二是創(chuàng)建輔助類,用來(lái)保存參數(shù)的聚集,這些輔助類的狀態(tài)通常是靜態(tài)的。
對(duì)于參數(shù)類型,優(yōu)先使用接口而不是類。
這樣做的目的是避免影響效能的拷貝操作。
謹(jǐn)慎的使用函數(shù)對(duì)象。
創(chuàng)建函數(shù)對(duì)象最容易的方法莫過(guò)于使用匿名類,但是那樣會(huì)帶來(lái)語(yǔ)法上混亂,并且與內(nèi)聯(lián)的控制結(jié)構(gòu)相比,這樣也會(huì)導(dǎo)致功能上的局限性。
Item 26:謹(jǐn)慎的使用重載
到底是什么造成了重載機(jī)制的混淆算法,這是個(gè)爭(zhēng)論的話題,一個(gè)安全而保守的方法是,永遠(yuǎn)不要導(dǎo)出兩個(gè)具有相同參數(shù)數(shù)目的重載方法。而對(duì)于構(gòu)造函數(shù)來(lái)說(shuō),一個(gè)類的多個(gè)構(gòu)造函數(shù)總是重載的,在某些情況下,我們可以選擇靜態(tài)工廠,但是對(duì)于構(gòu)造函數(shù)來(lái)說(shuō)這樣做并不總是切合實(shí)際的。
當(dāng)涉及到構(gòu)造函數(shù)時(shí),遵循這條建議也許是不可能的,但我們應(yīng)該極力避免下面的情形:
同一組參數(shù)只需要經(jīng)過(guò)類型的轉(zhuǎn)換就可以傳遞給不同的重載方法。如果這樣做也不能避免的話,我們至少要保證一點(diǎn):當(dāng)傳遞同樣的參數(shù)時(shí),所有的重載方法行為一致。如果不能做到這一點(diǎn),程序員就不能有效的使用方法或者構(gòu)造函數(shù)。
Item 27:返回零長(zhǎng)度的數(shù)組而不是null
因?yàn)檫@樣做的原因是編寫客戶程序的程序員可能忘記寫這種專門的代碼來(lái)處理null返回值。沒(méi)有理由從一個(gè)取數(shù)組值的方法中返回null,而不是返回一個(gè)零長(zhǎng)度數(shù)組。
Item 28:為所有導(dǎo)出的API元素編寫文檔注釋
不愛(ài)寫注釋可能是大多數(shù)程序員新手的通病(包括偶哈~),但是如果想要一個(gè)API真正可用,就必須寫一個(gè)文檔來(lái)說(shuō)明它,保持代碼和文檔的同步是一件比較煩瑣的事情,JAVA語(yǔ)言環(huán)境提供了javadoc工具,從而使這個(gè)煩瑣的過(guò)程變得容易,這個(gè)工具可以根據(jù)源代碼自動(dòng)產(chǎn)生API文檔。
為了正確得編寫API文檔,我們必須每一個(gè)被導(dǎo)出的類,接口,構(gòu)造函數(shù),方法和域聲明之前加一個(gè)文檔注釋。
每一個(gè)方法的文檔注釋應(yīng)該見(jiàn)解的描述它和客戶之間的約定。
我們接下來(lái)討論一下Java語(yǔ)言的細(xì)節(jié),包括局部變量的處理,庫(kù)的使用,以及兩種不是語(yǔ)言本身提供的機(jī)制的使用等等一些大家平時(shí)可能忽略的問(wèn)題。
Item 29:將局部變量的作用域最小化
和C語(yǔ)言要求局部變量必須被生命在代碼的開(kāi)始處相比,Java程序設(shè)計(jì)語(yǔ)言寬松得多,它允許你在代碼的任何位置聲明。要想使一個(gè)局部變量的作用域最小化,最高小的技術(shù)是在第一次需要使用它的地方聲明,變量的作用域是從聲明它的地方開(kāi)始到這個(gè)聲明做在的代碼塊的結(jié)束位止,如果我們把變量的聲明和代碼的使用位置分開(kāi)的過(guò)大,那么對(duì)于讀這段代碼的人來(lái)說(shuō),是很不幸的。
我們幾乎都是在一個(gè)局部變量聲明的地方同時(shí)給它初始化,注意這是很重要的,甚至有時(shí)候,如果我們的初始化應(yīng)該推遲到下一個(gè)代碼的位置,我們同時(shí)應(yīng)該把聲明也往后延遲。這條規(guī)則唯一的例外是try-catch這個(gè)語(yǔ)句,因?yàn)槿绻粋€(gè)變量被方法初始化,那么這個(gè)方法很有可能拋出一個(gè)異常,那我們最常用的方法就是把它置于try塊的內(nèi)部去進(jìn)行初始化。由此我們可以得出,for循環(huán)優(yōu)于while循環(huán),我們?cè)谀苁褂胒or循環(huán)的地方盡量使用for而不使用while,因?yàn)閒or循環(huán)是完全獨(dú)立的,所以重用循環(huán)變量名字不會(huì)有任何傷害。
最后我們要記住的是盡量把我們的函數(shù)寫的小而集中,這樣才能真正組做到”最小化局部變量的作用域”這一要旨。
Item 30:了解和使用庫(kù)
使用標(biāo)準(zhǔn)庫(kù),我們可以充分利用編寫這些庫(kù)的Java專家的知識(shí),以及在你之前其他人的使用經(jīng)驗(yàn),這就是所謂站在巨人的肩膀上看世界吧~
在每一個(gè)Java平臺(tái)的發(fā)行版本里面,都會(huì)有許多新的包的加入,和這些更新保持一直是值得的,比如說(shuō)我們J2ME的開(kāi)發(fā),在MIDP 1.0的時(shí)代,我們要寫個(gè)Game還要自己動(dòng)手寫工具類,現(xiàn)在MIDP2.0推出之后,大多數(shù)寫游戲的人都覺(jué)得方便了很多,因?yàn)樵谶@個(gè)版本里面加入了游戲包,為我們的開(kāi)發(fā)節(jié)省了大量的人力物力。
Item 31:如果想要知道精確的答案,就要避免使用double和float
     對(duì)于金融行業(yè)來(lái)說(shuō),對(duì)數(shù)據(jù)的嚴(yán)整性要求是很高的,不容半點(diǎn)馬虎,那大家都知道再我們的Java語(yǔ)言里面有兩個(gè)浮點(diǎn)數(shù)類型的變量float和double,可能大家會(huì)認(rèn)為他們的精度對(duì)于金融行業(yè)這樣對(duì)數(shù)字敏感的行業(yè)來(lái)說(shuō),已經(jīng)夠用了,但是在開(kāi)發(fā)當(dāng)中,我們要盡量少使用double和float,因?yàn)樽屗麄兙_的表達(dá)0.1是不可能的。那我們?nèi)绾谓鉀Q這個(gè)問(wèn)題呢,答案是使用BigDecimal,int或者long進(jìn)行貨幣計(jì)算。在這里對(duì)大家的忠告是:對(duì)于商務(wù)運(yùn)算,我們盡量使用BigDecimal,對(duì)于性能要求較高的地方,我們有能力自己處理十進(jìn)制的小數(shù)點(diǎn),數(shù)值不太大的時(shí)候,我們可以使用int或者long,根據(jù)自己的需要來(lái)判定具體使用哪一個(gè),如果范圍超過(guò)了18位數(shù),那我們必須使用BigDecimal。
Item 32:如果其他類型更適合,則盡量避免使用字符串
     在偶看到這條建議之前,我就很喜歡用字符串,不管在什么場(chǎng)合下,先String了再說(shuō),但是實(shí)際上很多情況下,我們要根據(jù)實(shí)際情況來(lái)判定到底使用什么類型,而且字符串不適合替代枚舉類型,類型安全枚舉類型和int值都比字符串更適合用來(lái)表示枚舉類型的常量。字符串也不適合替代聚集類型,有一個(gè)更好的方法就是簡(jiǎn)單的寫一個(gè)類來(lái)描述這個(gè)數(shù)據(jù)集,通常是一個(gè)私有的靜態(tài)成員類最好。字符串也不適合代替能力表,總而言之,如果可以適合更加適合的數(shù)據(jù)類型,或者可以編寫更加適當(dāng)?shù)臄?shù)據(jù)類型,那么應(yīng)該避免使用字符串來(lái)表示對(duì)象。
Item 33:了解字符串的連接功能
我們經(jīng)常在使用System.out.println()的時(shí)候,往括號(hào)里寫一串用“+”連接起來(lái)的字符串,這是我們最常見(jiàn)的,但是這個(gè)方法并不適合規(guī)模較大的情形,為連接N個(gè)字符串而重復(fù)地使用字符串連接操作符,要求N的平方級(jí)的時(shí)間,這是因?yàn)樽址欠强勺兊?,這就導(dǎo)致了在字符串進(jìn)行連接的時(shí)候,前后兩者都要拷貝,這個(gè)時(shí)候我們就提倡使用StingBuffer替代String。
Item 34:通過(guò)接口引用對(duì)象
通俗的說(shuō)就是盡量?jī)?yōu)先使用接口而不是類來(lái)引用對(duì)象,如果有合適的接口存在那么對(duì)使用參數(shù),返回值,變量域都應(yīng)該使用接口類型養(yǎng)成使用接口作為對(duì)象的習(xí)慣,會(huì)使程序變得更加靈活。
如果沒(méi)有合適的接口,那么,用類而不是接口來(lái)引用一個(gè)對(duì)象,是完全合適的。
Item 35:接口優(yōu)先于映像機(jī)制
java.lang.relect提供了“通過(guò)程序來(lái)訪問(wèn)關(guān)于已裝載的類的信息”,由此,我們可以通過(guò)一個(gè)給定的Class實(shí)例,獲得Constructor,Method和Field實(shí)例。
映像機(jī)制允許一個(gè)類使用另一個(gè)類,即使當(dāng)前編譯的時(shí)候后者還不存在,但是這種能力也要付出代價(jià):
我們損失了了編譯時(shí)類型檢查的好處,而且要求執(zhí)行映像訪問(wèn)的代碼非常笨拙和冗長(zhǎng),并且在性能上大大損失。
通常,普通應(yīng)用在運(yùn)行時(shí)刻不應(yīng)以映像方式訪問(wèn)對(duì)象。
Item 36:謹(jǐn)慎的使用本地方法
JNI允許Java應(yīng)用程序調(diào)用本地方法,所謂本地方法是指用本地程序設(shè)計(jì)語(yǔ)言(如C,C++)來(lái)編寫的特殊方法,本地方法可以在本地語(yǔ)言執(zhí)行任何計(jì)算任務(wù),然后返回到Java程序設(shè)計(jì)語(yǔ)言中。但是隨著JDK1.3及后續(xù)版本的推出這種通過(guò)使用本地方法來(lái)提高性能的方法已不值得提倡,因?yàn)楝F(xiàn)在的JVM越來(lái)越快了,而且使用本地方法有一些嚴(yán)重的缺點(diǎn),比如使Java原本引以為傲的安全性蕩然無(wú)存,總之在使用本地方法的時(shí)候要三思。
Item 37:謹(jǐn)慎使用優(yōu)化
不要因?yàn)樾阅芏鵂奚侠淼拇a結(jié)構(gòu),努力編寫好的程序而不是快的程序,但是避免那些限制性能的設(shè)計(jì)決定,同時(shí)考慮自己設(shè)計(jì)的API決定的性能后果,為了獲得更好的性能而對(duì)API進(jìn)行修改這也是一個(gè)非常不好的想法,通常我們?cè)谧鰞?yōu)化之后,都應(yīng)該對(duì)優(yōu)化的程度進(jìn)行一些測(cè)量。
Item 38:遵守普遍接受的命名慣例
Java有一套比較完善的命名慣例機(jī)制,大部分包含在《The Java Language Specification》,嚴(yán)格得講這些慣例分成兩類,字面的和語(yǔ)法的。
字面涉及包,類,接口,方法和域,語(yǔ)法的命名慣例比較靈活,所以爭(zhēng)議更大,字面慣例是非常直接和明確的,而語(yǔ)法慣例則相對(duì)復(fù)雜,也很松散。但是有一個(gè)公認(rèn)的做法是:“如果長(zhǎng)期養(yǎng)成的習(xí)慣用法與此不同的話,請(qǐng)不要盲目遵從
Item 12:把類和成員的可訪問(wèn)范圍降到最低
    好的模塊設(shè)計(jì)應(yīng)該盡最大可能封裝好自己的內(nèi)部信息,這樣可以把模塊之間的耦合程度降到最低。開(kāi)發(fā)得以并行,無(wú)疑這將加快開(kāi)發(fā)的速度,便于系統(tǒng)地維護(hù)。Java中通過(guò)訪問(wèn)控制符來(lái)解決這個(gè)問(wèn)題。
public表示這個(gè)類在任何范圍都可用。
protected表示只有子類和包內(nèi)的類可以使用
private-package(default)表示在包內(nèi)可用
private表示只有類內(nèi)才可以用
你在設(shè)計(jì)一個(gè)類的時(shí)候應(yīng)該盡量的按照4321得順序設(shè)計(jì)。如果一個(gè)類只是被另一個(gè)類使用,那么應(yīng)該考慮把它設(shè)計(jì)成這個(gè)類的內(nèi)部類。通常public的類不應(yīng)該有public得字段,不過(guò)我們通常會(huì)用一個(gè)類來(lái)定義所有的常量,這是允許的。不過(guò)必須保證這些字段要么是基本數(shù)據(jù)類型要么引用指向的對(duì)象是不可修改的。不然他們將可能被修改。例如下面的定義中data就是不合理的,后面兩個(gè)沒(méi)有問(wèn)題。
public class Con
{
      public static final int[] data = {1,2,3};// it is bad
      public static final String hello = "world";
      public static final int i = 1;
}
Item 13:不可修改的類更受青睞
    不可修改的類意思是他們一經(jīng)創(chuàng)建就不會(huì)改變,例如String類。他們的設(shè)計(jì)、實(shí)現(xiàn)都很方便,安全性高——它們是線程安全的。設(shè)計(jì)不可修改類有幾點(diǎn)規(guī)則:
不要提供任何可以修改對(duì)象的方法
確保沒(méi)有方法能夠被覆蓋,可以通過(guò)把它聲明為final
所有字段設(shè)計(jì)成final
所有字段設(shè)計(jì)成private
確保外部不能訪問(wèn)到類的可修改的組件
不可修改類也有個(gè)缺點(diǎn)就是創(chuàng)建不同值得類的時(shí)候要?jiǎng)?chuàng)建不同的對(duì)象,String就是這樣的。通常有個(gè)解決的辦法就是提供一個(gè)幫助類來(lái)彌補(bǔ),例如StringBuffer類。
Item 14:化合(合成)比繼承更值得考慮
      實(shí)現(xiàn)代碼重用最重要的辦法就是繼承,但是繼承破壞了封裝,導(dǎo)致軟件的鍵壯性不足。如果子類繼承了父類,那么它從父類繼承的方法就依賴父類的實(shí)現(xiàn),一旦他改變了會(huì)導(dǎo)致不可預(yù)測(cè)的結(jié)果。作者介紹了InstrumentedHashSet作為反例進(jìn)行說(shuō)明,原因就是沒(méi)有明白父類的方法實(shí)現(xiàn)。作者給出的解決辦法是通過(guò)化合來(lái)代替繼承,用包裝類和轉(zhuǎn)發(fā)方法來(lái)解決問(wèn)題。把想擴(kuò)展的類作為本類的一個(gè)private final得成員變量。把方法參數(shù)傳遞給這個(gè)成員變量并得到返回值。這樣做的缺點(diǎn)是這樣的類不適合回掉框架。繼承雖然好,我們卻不應(yīng)該濫用,只有我們能確定它們之間是is-a得關(guān)系的時(shí)候才使用。
Item 15:如果要用繼承那么設(shè)計(jì)以及文檔都要有質(zhì)量保證,否則就不要用它
    為了避免繼承帶來(lái)的問(wèn)題,你必須提供精確的文檔來(lái)說(shuō)明覆蓋相關(guān)方法可能出現(xiàn)的問(wèn)題。在構(gòu)造器內(nèi)千萬(wàn)不要調(diào)用可以被覆蓋的方法,因?yàn)樽宇惛采w方法的時(shí)候會(huì)出現(xiàn)問(wèn)題。
import java.util.*;
public class SubClass extends SuperClass
{
 private final Date date;
 
 public SubClass()
 {
  date = new Date();
 }
 
 public void m()
 {
  System.out.println(date);
 }
 
 public static void main(String[] args)
 {
  SubClass s = new SubClass();
  s.m();
 }
 
}
class SuperClass
{
 public SuperClass()
 {
  m();
 }
 
 public void m()
 {
 
 }
}
由于在date被初始化之前super()已經(jīng)被調(diào)用了,所以第一次輸出null而不是當(dāng)前的時(shí)間。
由于在Clone()或者序列化的時(shí)候非常類似構(gòu)造器的功能,因此readObject()和clone()方法內(nèi)最好也不要包括能被覆蓋的方法。
Item 16:在接口和抽象類之間優(yōu)先選擇前者
      接口和抽象類都用來(lái)實(shí)現(xiàn)多態(tài),不過(guò)我們應(yīng)該優(yōu)先考慮用接口。知道嗎?James說(shuō)過(guò)如果要讓他重新設(shè)計(jì)java的話他會(huì)把所有都設(shè)計(jì)成接口的。抽象類的優(yōu)點(diǎn)是方便擴(kuò)展,因?yàn)樗潜焕^承的,并且方法可以在抽象類內(nèi)實(shí)現(xiàn),接口則不行。
Item 17:接口只應(yīng)該用來(lái)定義類型
      接口可以這樣用的 Collection c = new xxxx();這是我們最常用的。不要把接口用來(lái)做其他的事情,比如常量的定義。你應(yīng)該定義一個(gè)類,里面包含public final static 得字段。
Item 18: 在靜態(tài)和非靜態(tài)內(nèi)部類之間選擇前者
      如果一個(gè)類被定義在其他的類內(nèi)部那么它就是嵌套類,可以分為靜態(tài)內(nèi)部類、非靜態(tài)內(nèi)部類和匿名類。
   static member class 得目的是為enclosing class服務(wù),如果還有其他的目的,就應(yīng)該把它設(shè)計(jì)成top-level class。nonstatic member class是和enclosing class instance關(guān)聯(lián)的,如果不需要訪問(wèn)enclosing class instance的話應(yīng)該把它設(shè)計(jì)成static得,不然會(huì)浪費(fèi)時(shí)間和空間。anonymous class是聲明和初始化同時(shí)進(jìn)行的。可以放在代碼的任意位置。典型應(yīng)用是Listener 和process object例如Thread。
    由于以前學(xué)過(guò)C語(yǔ)言,所以對(duì)C還是蠻有感情,而JAVA和C又有很多相似之處,很多從C轉(zhuǎn)過(guò)來(lái)學(xué)習(xí)JAVA的兄弟,可能一開(kāi)始都不是很適應(yīng),因?yàn)楹芏嘣贑里面的結(jié)構(gòu)在JAVA里面都不能使用了,所以下面我們來(lái)介紹一下C語(yǔ)言結(jié)構(gòu)的替代。
Item 19:用類代替結(jié)構(gòu)
      JAVA剛面世的時(shí)候,很多C程序員都認(rèn)為用類來(lái)代替結(jié)構(gòu)現(xiàn)在太復(fù)雜,代價(jià)太大了,但是實(shí)際上,如果一個(gè)JAVA的類退化到只包含一個(gè)數(shù)據(jù)域的話,這樣的類與C語(yǔ)言的結(jié)構(gòu)大致是等價(jià)的。
      比方說(shuō)下面兩個(gè)程序片段:
      class Point
      {
       private float x;
       private float y;
      }
      實(shí)際上這段代碼和C語(yǔ)言的結(jié)構(gòu)基本上沒(méi)什么區(qū)別,但是這段代碼恐怕是眾多OO設(shè)計(jì)Fans所不齒的,因?yàn)樗鼪](méi)有體現(xiàn)封裝的優(yōu)異性,沒(méi)有體現(xiàn)面向?qū)ο笤O(shè)計(jì)的優(yōu)點(diǎn),當(dāng)一個(gè)域被修改的時(shí)候,你不可能再采取任何輔助的措施了,那我們?cè)賮?lái)看一看采用包含私有域和共有訪問(wèn)方法的OO設(shè)計(jì)代碼段:
      class Point
      {
       private float x;
       private float y;
       public Point(float x,float y)
       {
             this.x=x;
             this.y=y;
       }
        public float getX(){retrun x;}
        public float getY(){return y;}
        public void setX(float x){this.x=x;}
        public void setY(float y){this.y=y;}
      }
        單從表面上看,這段代碼比上面那個(gè)多了很多行,還多了很多函數(shù),但是仔細(xì)想一下,這樣的OO設(shè)計(jì),似乎更人性化,我們可以方面的對(duì)值域進(jìn)行提取,修改等操作,而不直接和值域發(fā)生關(guān)系,這樣的代碼不僅讓人容易讀懂,而且很安全,還吸取了面向?qū)ο蟪绦蛟O(shè)計(jì)的靈活性,試想一下,如果一個(gè)共有類暴露它的值域,那么想要在將來(lái)的版本中進(jìn)行修改是impossible的,因?yàn)楣灿蓄惖目蛻舸a已經(jīng)遍布各處了。
需要提醒一點(diǎn)的是,如果一個(gè)類是包級(jí)私有的,或者是一個(gè)私有的嵌套類,則直接暴露其值域并無(wú)不妥之處。
Item 20:用類層次來(lái)代替聯(lián)合
我們?cè)谟肅語(yǔ)言來(lái)進(jìn)行開(kāi)發(fā)的時(shí)候,經(jīng)常會(huì)用到聯(lián)合這個(gè)概念,比如:
       typedef struct{
     double length;
     double width;    
}rectangleDimensions_t;
那我們?cè)贘AVA里面沒(méi)有聯(lián)合這個(gè)概念,那我們用什么呢?對(duì)!用繼承,這也是JAVA最吸引我的地方之一,它可以使用更好的機(jī)制來(lái)定義耽擱數(shù)據(jù)類型,在Bruce Eckel的Thinking in java里面也多次提到了一個(gè)和形狀有關(guān)的例子,我們可以先籠統(tǒng)的定義一個(gè)抽象類,即我們通常所指的超類,每個(gè)操作定義一個(gè)抽象的方法,其行為取決于標(biāo)簽的值,如果還有其他的操作不依賴于標(biāo)簽的值,則把操作變成根類(繼承的類)中的具體方法。
這樣做的最重要的優(yōu)點(diǎn)是:類層次提供了類型的安全性。
其次代碼非常明了,這也是OO設(shè)計(jì)的優(yōu)點(diǎn)。
而且它很容易擴(kuò)展,即使是面向多個(gè)方面的工作,能夠同樣勝任。
最后它可以反映這些類型之間本質(zhì)上的層次關(guān)系,從而允許更強(qiáng)的靈活性,以便編譯時(shí)類型檢查。
Item 21:用類來(lái)代替enum結(jié)構(gòu)
Java程序設(shè)計(jì)語(yǔ)言提出了類型安全枚舉的模式來(lái)替代enum結(jié)構(gòu),它的基本思想很簡(jiǎn)單:定義一個(gè)類來(lái)代表枚舉類型的單個(gè)元素,并且不提供任何公有的構(gòu)造函數(shù),相反,提供公有靜態(tài)final類,使枚舉類型中的每一個(gè)常量都對(duì)應(yīng)一個(gè)域。
類型安全枚舉類型的一個(gè)缺點(diǎn)是,裝載枚舉類的和構(gòu)造常量對(duì)象時(shí),需要一定的時(shí)間和空間開(kāi)銷,除非是在資源很受限制的設(shè)備比如蜂窩電哈和烤面包機(jī)上,否則在實(shí)際中這個(gè)問(wèn)題不會(huì)被考慮。
 總之,類型安全枚舉類型明顯優(yōu)于int類型,除非實(shí)在一個(gè)枚舉類型主要被用做一個(gè)集合元素,或者主要用在一個(gè)資源非常不受限的環(huán)境下,否則類型安全枚舉類型的缺點(diǎn)都不成問(wèn)題,依次,在要求使用一個(gè)枚舉類型的環(huán)境下,我們首先應(yīng)考慮類型安全枚舉類型模式。
Item 22:用類和接口來(lái)代替函數(shù)指針
 class StringLengthComprator{
public int compare(String s1,String s2)
{
return s1.length()-s2.length();
}
}
這個(gè)類導(dǎo)出一個(gè)帶兩個(gè)字符串的方法,它是一個(gè)用于字符串比較的具體策略。它是無(wú)狀態(tài)的,沒(méi)有域,所以,這個(gè)類的所有實(shí)例在功能上都是等價(jià)的,可以節(jié)省不必要的對(duì)象創(chuàng)建開(kāi)銷。但是我們不好直接把這個(gè)類傳遞給可戶使用,因?yàn)榭蓱魺o(wú)法傳遞任何其他的比較策略。相反,我們可以定義一個(gè)接口,即我們?cè)谠O(shè)計(jì)具體策略類的時(shí)候還需要定義一個(gè)策略接口:
      public interface Comparator{
           public int compare(Object o1,Object o2);
}
  我們完全可以依照自己的需要來(lái)定義它。
在JAVA中,我們?yōu)榱藢?shí)現(xiàn)指針的模式,聲明一個(gè)接口來(lái)表示該策略,并且為每個(gè)具體策略聲明一個(gè)實(shí)現(xiàn)了該接口的類,如果一個(gè)具體策略只被使用一次的話,那么通常使用匿名類來(lái)聲明和實(shí)例化這個(gè)具體策略類,如果一個(gè)策略類反復(fù)使用,那么它的類通常是一個(gè)私有的的靜態(tài)成員類。
下面我們來(lái)討論一下有關(guān)方法設(shè)計(jì)的幾個(gè)方面,下面說(shuō)的幾個(gè)要點(diǎn)大多數(shù)都是應(yīng)用在構(gòu)造函數(shù)中,當(dāng)然也使用于普通方法,我們追求的依然是程序的可用性,健壯性和靈活性。
Item 23:檢查參數(shù)的有效性
非公有的方法我們應(yīng)該用斷言的方法來(lái)檢查它的參數(shù),而不是使用通常大家所熟悉的檢查語(yǔ)句來(lái)檢測(cè)。如果我們使用的開(kāi)發(fā)平臺(tái)是JDK1.4或者更高級(jí)的平臺(tái),我們可以使用assert結(jié)構(gòu);否則我們應(yīng)該使用一種臨時(shí)的斷言機(jī)制。
有些參數(shù)在使用過(guò)程中是先保存起來(lái),然后在使用的時(shí)候再進(jìn)行調(diào)用,構(gòu)造函數(shù)正是這種類型的一種體現(xiàn),所以我們通常對(duì)構(gòu)造函數(shù)參數(shù)的有效性檢查是非常仔細(xì)的。
Item 24:需要時(shí)使用保護(hù)性拷貝
眾所周知,JAVA在代碼安全性方面較C/C++有顯著的提高,緩沖區(qū)溢出,數(shù)組越界,非法指針等等,我們的JAVA都有一個(gè)很完善的機(jī)制來(lái)進(jìn)行免疫,但是這并不代表我們不必去考慮JAVA的安全性,即便在安全的語(yǔ)言,如果不采取措施,還是無(wú)法使自己與其他類隔開(kāi)。假設(shè)類的客戶會(huì)盡一切手段來(lái)破壞這個(gè)類的約束條件,在這樣的前提下,你必須從保護(hù)性的方面來(lái)考慮設(shè)計(jì)程序。通過(guò)大量的程序代碼研究我們得出這樣的結(jié)論:對(duì)于構(gòu)造性函數(shù)的每個(gè)可變參數(shù)進(jìn)行保護(hù)性拷貝是必要的。需要注意的是,保護(hù)性拷貝是在檢查參數(shù)的有效性之前 進(jìn)行的,并且有效性檢查是針對(duì)拷貝之后的對(duì)象,而不是原始的對(duì)象。對(duì)于“參數(shù)類型可以被不可信方子類化”的情況,不要用clone方法來(lái)進(jìn)行參數(shù)的保護(hù)性拷貝。
對(duì)于參數(shù)的保護(hù)性拷貝并不僅僅在于非可變類,當(dāng)我們編寫一個(gè)函數(shù)或者一個(gè)構(gòu)造函數(shù)的時(shí)候,如果它要接受客戶提供的對(duì)象,允許該對(duì)象進(jìn)入到內(nèi)部數(shù)據(jù)結(jié)構(gòu)中,則有必要考慮一下,客戶提供的對(duì)象是否是可變的,如果是,則要考慮其變化的范圍是否在你的程序所能容納的范圍內(nèi),如果不是,則要對(duì)對(duì)象進(jìn)行保護(hù)性拷貝,并且讓拷貝之后的對(duì)象而不是原始對(duì)象進(jìn)入到數(shù)據(jù)結(jié)構(gòu)中去。當(dāng)然最好的解決方法是使用非可變的對(duì)象作為你的對(duì)象內(nèi)部足見(jiàn),這樣你就可以不必關(guān)心保護(hù)性拷貝問(wèn)題了。):
Item 25:謹(jǐn)慎使用設(shè)計(jì)方法的原型
(1)謹(jǐn)慎的選擇方法的名字:即要注意首先要是易于理解的,其次還要與該包中的其他方法的命名風(fēng)格相一致,最后當(dāng)然要注意取一個(gè)大眾所認(rèn)可的名字。
(2)不要追求提供便利的方法:每一個(gè)方法都應(yīng)該提供其應(yīng)具備的功能點(diǎn),對(duì)于接口和類來(lái)方法不要過(guò)多,否則會(huì)對(duì)學(xué)習(xí)使用維護(hù)等等方面帶來(lái)許多不必要的麻煩,對(duì)于每一個(gè)類型所支持的每一個(gè)動(dòng)作,都提供一個(gè)功能完全的方法,只有一個(gè)方法過(guò)于頻繁的使用時(shí),才考慮為它提供一個(gè)快捷方法。
(3)避免過(guò)長(zhǎng)的參數(shù)列表:通常在實(shí)踐中,我們以三個(gè)參數(shù)作為最大值,參數(shù)越少越好,類型相同的長(zhǎng)參數(shù)列尤其影響客戶的使用,兩個(gè)方法可以避免過(guò)長(zhǎng)的參數(shù)這樣的情況發(fā)生,一是把一個(gè)方法分解成多個(gè),每一個(gè)方法只要求使用這些參數(shù)的一個(gè)子集;二是創(chuàng)建輔助類,用來(lái)保存參數(shù)的聚集,這些輔助類的狀態(tài)通常是靜態(tài)的。
對(duì)于參數(shù)類型,優(yōu)先使用接口而不是類。
這樣做的目的是避免影響效能的拷貝操作。
謹(jǐn)慎的使用函數(shù)對(duì)象。
創(chuàng)建函數(shù)對(duì)象最容易的方法莫過(guò)于使用匿名類,但是那樣會(huì)帶來(lái)語(yǔ)法上混亂,并且與內(nèi)聯(lián)的控制結(jié)構(gòu)相比,這樣也會(huì)導(dǎo)致功能上的局限性。
Item 26:謹(jǐn)慎的使用重載
到底是什么造成了重載機(jī)制的混淆算法,這是個(gè)爭(zhēng)論的話題,一個(gè)安全而保守的方法是,永遠(yuǎn)不要導(dǎo)出兩個(gè)具有相同參數(shù)數(shù)目的重載方法。而對(duì)于構(gòu)造函數(shù)來(lái)說(shuō),一個(gè)類的多個(gè)構(gòu)造函數(shù)總是重載的,在某些情況下,我們可以選擇靜態(tài)工廠,但是對(duì)于構(gòu)造函數(shù)來(lái)說(shuō)這樣做并不總是切合實(shí)際的。
當(dāng)涉及到構(gòu)造函數(shù)時(shí),遵循這條建議也許是不可能的,但我們應(yīng)該極力避免下面的情形:
同一組參數(shù)只需要經(jīng)過(guò)類型的轉(zhuǎn)換就可以傳遞給不同的重載方法。如果這樣做也不能避免的話,我們至少要保證一點(diǎn):當(dāng)傳遞同樣的參數(shù)時(shí),所有的重載方法行為一致。如果不能做到這一點(diǎn),程序員就不能有效的使用方法或者構(gòu)造函數(shù)。
Item 27:返回零長(zhǎng)度的數(shù)組而不是null
因?yàn)檫@樣做的原因是編寫客戶程序的程序員可能忘記寫這種專門的代碼來(lái)處理null返回值。沒(méi)有理由從一個(gè)取數(shù)組值的方法中返回null,而不是返回一個(gè)零長(zhǎng)度數(shù)組。
Item 28:為所有導(dǎo)出的API元素編寫文檔注釋
不愛(ài)寫注釋可能是大多數(shù)程序員新手的通病(包括偶哈~),但是如果想要一個(gè)API真正可用,就必須寫一個(gè)文檔來(lái)說(shuō)明它,保持代碼和文檔的同步是一件比較煩瑣的事情,JAVA語(yǔ)言環(huán)境提供了javadoc工具,從而使這個(gè)煩瑣的過(guò)程變得容易,這個(gè)工具可以根據(jù)源代碼自動(dòng)產(chǎn)生API文檔。
為了正確得編寫API文檔,我們必須每一個(gè)被導(dǎo)出的類,接口,構(gòu)造函數(shù),方法和域聲明之前加一個(gè)文檔注釋。
每一個(gè)方法的文檔注釋應(yīng)該見(jiàn)解的描述它和客戶之間的約定。
我們接下來(lái)討論一下Java語(yǔ)言的細(xì)節(jié),包括局部變量的處理,庫(kù)的使用,以及兩種不是語(yǔ)言本身提供的機(jī)制的使用等等一些大家平時(shí)可能忽略的問(wèn)題。
Item 29:將局部變量的作用域最小化
和C語(yǔ)言要求局部變量必須被生命在代碼的開(kāi)始處相比,Java程序設(shè)計(jì)語(yǔ)言寬松得多,它允許你在代碼的任何位置聲明。要想使一個(gè)局部變量的作用域最小化,最高小的技術(shù)是在第一次需要使用它的地方聲明,變量的作用域是從聲明它的地方開(kāi)始到這個(gè)聲明做在的代碼塊的結(jié)束位止,如果我們把變量的聲明和代碼的使用位置分開(kāi)的過(guò)大,那么對(duì)于讀這段代碼的人來(lái)說(shuō),是很不幸的。
我們幾乎都是在一個(gè)局部變量聲明的地方同時(shí)給它初始化,注意這是很重要的,甚至有時(shí)候,如果我們的初始化應(yīng)該推遲到下一個(gè)代碼的位置,我們同時(shí)應(yīng)該把聲明也往后延遲。這條規(guī)則唯一的例外是try-catch這個(gè)語(yǔ)句,因?yàn)槿绻粋€(gè)變量被方法初始化,那么這個(gè)方法很有可能拋出一個(gè)異常,那我們最常用的方法就是把它置于try塊的內(nèi)部去進(jìn)行初始化。由此我們可以得出,for循環(huán)優(yōu)于while循環(huán),我們?cè)谀苁褂胒or循環(huán)的地方盡量使用for而不使用while,因?yàn)閒or循環(huán)是完全獨(dú)立的,所以重用循環(huán)變量名字不會(huì)有任何傷害。
最后我們要記住的是盡量把我們的函數(shù)寫的小而集中,這樣才能真正組做到”最小化局部變量的作用域”這一要旨。
Item 30:了解和使用庫(kù)
使用標(biāo)準(zhǔn)庫(kù),我們可以充分利用編寫這些庫(kù)的Java專家的知識(shí),以及在你之前其他人的使用經(jīng)驗(yàn),這就是所謂站在巨人的肩膀上看世界吧~
在每一個(gè)Java平臺(tái)的發(fā)行版本里面,都會(huì)有許多新的包的加入,和這些更新保持一直是值得的,比如說(shuō)我們J2ME的開(kāi)發(fā),在MIDP 1.0的時(shí)代,我們要寫個(gè)Game還要自己動(dòng)手寫工具類,現(xiàn)在MIDP2.0推出之后,大多數(shù)寫游戲的人都覺(jué)得方便了很多,因?yàn)樵谶@個(gè)版本里面加入了游戲包,為我們的開(kāi)發(fā)節(jié)省了大量的人力物力。
Item 31:如果想要知道精確的答案,就要避免使用double和float
     對(duì)于金融行業(yè)來(lái)說(shuō),對(duì)數(shù)據(jù)的嚴(yán)整性要求是很高的,不容半點(diǎn)馬虎,那大家都知道再我們的Java語(yǔ)言里面有兩個(gè)浮點(diǎn)數(shù)類型的變量float和double,可能大家會(huì)認(rèn)為他們的精度對(duì)于金融行業(yè)這樣對(duì)數(shù)字敏感的行業(yè)來(lái)說(shuō),已經(jīng)夠用了,但是在開(kāi)發(fā)當(dāng)中,我們要盡量少使用double和float,因?yàn)樽屗麄兙_的表達(dá)0.1是不可能的。那我們?nèi)绾谓鉀Q這個(gè)問(wèn)題呢,答案是使用BigDecimal,int或者long進(jìn)行貨幣計(jì)算。在這里對(duì)大家的忠告是:對(duì)于商務(wù)運(yùn)算,我們盡量使用BigDecimal,對(duì)于性能要求較高的地方,我們有能力自己處理十進(jìn)制的小數(shù)點(diǎn),數(shù)值不太大的時(shí)候,我們可以使用int或者long,根據(jù)自己的需要來(lái)判定具體使用哪一個(gè),如果范圍超過(guò)了18位數(shù),那我們必須使用BigDecimal。
Item 32:如果其他類型更適合,則盡量避免使用字符串
     在偶看到這條建議之前,我就很喜歡用字符串,不管在什么場(chǎng)合下,先String了再說(shuō),但是實(shí)際上很多情況下,我們要根據(jù)實(shí)際情況來(lái)判定到底使用什么類型,而且字符串不適合替代枚舉類型,類型安全枚舉類型和int值都比字符串更適合用來(lái)表示枚舉類型的常量。字符串也不適合替代聚集類型,有一個(gè)更好的方法就是簡(jiǎn)單的寫一個(gè)類來(lái)描述這個(gè)數(shù)據(jù)集,通常是一個(gè)私有的靜態(tài)成員類最好。字符串也不適合代替能力表,總而言之,如果可以適合更加適合的數(shù)據(jù)類型,或者可以編寫更加適當(dāng)?shù)臄?shù)據(jù)類型,那么應(yīng)該避免使用字符串來(lái)表示對(duì)象。
Item 33:了解字符串的連接功能
我們經(jīng)常在使用System.out.println()的時(shí)候,往括號(hào)里寫一串用“+”連接起來(lái)的字符串,這是我們最常見(jiàn)的,但是這個(gè)方法并不適合規(guī)模較大的情形,為連接N個(gè)字符串而重復(fù)地使用字符串連接操作符,要求N的平方級(jí)的時(shí)間,這是因?yàn)樽址欠强勺兊模@就導(dǎo)致了在字符串進(jìn)行連接的時(shí)候,前后兩者都要拷貝,這個(gè)時(shí)候我們就提倡使用StingBuffer替代String。
Item 34:通過(guò)接口引用對(duì)象
通俗的說(shuō)就是盡量?jī)?yōu)先使用接口而不是類來(lái)引用對(duì)象,如果有合適的接口存在那么對(duì)使用參數(shù),返回值,變量域都應(yīng)該使用接口類型養(yǎng)成使用接口作為對(duì)象的習(xí)慣,會(huì)使程序變得更加靈活。
如果沒(méi)有合適的接口,那么,用類而不是接口來(lái)引用一個(gè)對(duì)象,是完全合適的。
Item 35:接口優(yōu)先于映像機(jī)制
java.lang.relect提供了“通過(guò)程序來(lái)訪問(wèn)關(guān)于已裝載的類的信息”,由此,我們可以通過(guò)一個(gè)給定的Class實(shí)例,獲得Constructor,Method和Field實(shí)例。
映像機(jī)制允許一個(gè)類使用另一個(gè)類,即使當(dāng)前編譯的時(shí)候后者還不存在,但是這種能力也要付出代價(jià):
我們損失了了編譯時(shí)類型檢查的好處,而且要求執(zhí)行映像訪問(wèn)的代碼非常笨拙和冗長(zhǎng),并且在性能上大大損失。
通常,普通應(yīng)用在運(yùn)行時(shí)刻不應(yīng)以映像方式訪問(wèn)對(duì)象。
Item 36:謹(jǐn)慎的使用本地方法
JNI允許Java應(yīng)用程序調(diào)用本地方法,所謂本地方法是指用本地程序設(shè)計(jì)語(yǔ)言(如C,C++)來(lái)編寫的特殊方法,本地方法可以在本地語(yǔ)言執(zhí)行任何計(jì)算任務(wù),然后返回到Java程序設(shè)計(jì)語(yǔ)言中。但是隨著JDK1.3及后續(xù)版本的推出這種通過(guò)使用本地方法來(lái)提高性能的方法已不值得提倡,因?yàn)楝F(xiàn)在的JVM越來(lái)越快了,而且使用本地方法有一些嚴(yán)重的缺點(diǎn),比如使Java原本引以為傲的安全性蕩然無(wú)存,總之在使用本地方法的時(shí)候要三思。
Item 37:謹(jǐn)慎使用優(yōu)化
不要因?yàn)樾阅芏鵂奚侠淼拇a結(jié)構(gòu),努力編寫好的程序而不是快的程序,但是避免那些限制性能的設(shè)計(jì)決定,同時(shí)考慮自己設(shè)計(jì)的API決定的性能后果,為了獲得更好的性能而對(duì)API進(jìn)行修改這也是一個(gè)非常不好的想法,通常我們?cè)谧鰞?yōu)化之后,都應(yīng)該對(duì)優(yōu)化的程度進(jìn)行一些測(cè)量。
Item 38:遵守普遍接受的命名慣例
Java有一套比較完善的命名慣例機(jī)制,大部分包含在《The Java Language Specification》,嚴(yán)格得講這些慣例分成兩類,字面的和語(yǔ)法的。
字面涉及包,類,接口,方法和域,語(yǔ)法的命名慣例比較靈活,所以爭(zhēng)議更大,字面慣例是非常直接和明確的,而語(yǔ)法慣例則相對(duì)復(fù)雜,也很松散。但是有一個(gè)公認(rèn)的做法是:“如果長(zhǎng)期養(yǎng)成的習(xí)慣用法與此不同的話,請(qǐng)不要盲目遵從


]]>
《Practical Java》筆記http://www.aygfsteel.com/gufen/archive/2005/09/25/13992.html落花飛雪落花飛雪Sun, 25 Sep 2005 07:22:00 GMThttp://www.aygfsteel.com/gufen/archive/2005/09/25/13992.htmlhttp://www.aygfsteel.com/gufen/comments/13992.htmlhttp://www.aygfsteel.com/gufen/archive/2005/09/25/13992.html#Feedback4http://www.aygfsteel.com/gufen/comments/commentRss/13992.htmlhttp://www.aygfsteel.com/gufen/services/trackbacks/13992.html1. 聲明是什么?
String s = "Hello world!";

許多人都做過(guò)這樣的事情,但是,我們到底聲明了什么?回答通常是:一個(gè)String,內(nèi)容是“Hello world!”。這樣模糊的回答通常是概念不清的根源。如果要準(zhǔn)確的回答,一半的人大概會(huì)回答錯(cuò)誤。
這個(gè)語(yǔ)句聲明的是一個(gè)指向?qū)ο蟮囊?,名為“s”,可以指向類型為String的任何對(duì)象,目前指

1. 聲明是什么?
String s = "Hello world!";

許多人都做過(guò)這樣的事情,但是,我們到底聲明了什么?回答通常是:一個(gè)String,內(nèi)容是“Hello world!”。這樣模糊的回答通常是概念不清的根源。如果要準(zhǔn)確的回答,一半的人大概會(huì)回答錯(cuò)誤。
這個(gè)語(yǔ)句聲明的是一個(gè)指向?qū)ο蟮囊?,名為“s”,可以指向類型為String的任何對(duì)象,目前指向"Hello world!"這個(gè)String類型的對(duì)象。這就是真正發(fā)生的事情。我們并沒(méi)有聲明一個(gè)String對(duì)象,我們只是聲明了一個(gè)只能指向String對(duì)象的引用變量。所以,如果在剛才那句語(yǔ)句后面,如果再運(yùn)行一句:

String string = s;

我們是聲明了另外一個(gè)只能指向String對(duì)象的引用,名為string,并沒(méi)有第二個(gè)對(duì)象產(chǎn)生,string還是指向原來(lái)那個(gè)對(duì)象,也就是,和s指向同一個(gè)對(duì)象。
2. String類的特殊性
1) String s1 = “Hello”;  //產(chǎn)生一個(gè)String ”Hello”對(duì)象,并產(chǎn)生該對(duì)象的一個(gè)別名s1來(lái)引用該對(duì)象
String s2 = “Hello”;  //又產(chǎn)生一個(gè)別名s2來(lái)引用上面的”Hello”對(duì)象
s1 == s2 = true;   //由于是同一個(gè)對(duì)象所以“==”返回為true
s1 = “World”;  //產(chǎn)生一個(gè)String ”World”對(duì)象, s1的引用不再指向“Hello”而是指向?qū)ο蟆盬orld”
s1 == s2 = false;   //由于不是同一個(gè)對(duì)象所以“==”返回為false
s1 = “Hello”;  //同上面的String s2 = “Hello”; 現(xiàn)在s1又指向?qū)ο蟆盚ello”, 因?yàn)镴VM會(huì)自動(dòng)根據(jù)棧中數(shù)據(jù)的實(shí)際情況來(lái)決定是否有必要?jiǎng)?chuàng)建新對(duì)象。
s1 == s2 = true;   //由于是同一個(gè)對(duì)象所以“==”又返回為true了
s1 = s1 + “World”;  //這時(shí)又產(chǎn)生一個(gè)對(duì)象”HelloWord”,s1不再指向”Hello”而是指向”HelloWord”
s1 == s2 = false;  //不是一個(gè)對(duì)象當(dāng)然是false拉
s1 = s1+ "a"+"b"+"c"+…;  // String不停的創(chuàng)建對(duì)象,影響性能,這種易變的String用StringBuffer會(huì)得到更好的性能
StringBuffer s3 = new StringBuffer(“Hello”);
s3.append(“a”); //沒(méi)有生成新的對(duì)象,而是將s3引用的對(duì)象內(nèi)容改為”Helloa”

//說(shuō)明: String類用來(lái)表示那些創(chuàng)建后就不會(huì)再改變的字符串,它是immutable的。而StringBuffer類用來(lái)表示內(nèi)容可變的字符串,并提供了修改底層字符串的方法。
StingBuffer是一個(gè)可變的字符串,它可以被更改。同時(shí)StringBuffer是Thread safe的, 你可以放心的使用.

因?yàn)镾tring被設(shè)計(jì)成一種安全的字符串, 避免了C/C++中的尷尬。因此在內(nèi)部操作的時(shí)候會(huì)頻繁的進(jìn)行對(duì)象的交換, 因此它的效率不如StringBuffer。 如果需要頻繁的進(jìn)行字符串的增刪操作的話最好用StringBuffer。 比如拼SQL文, 寫共函。 另: 編繹器對(duì)String的+操作進(jìn)行了一定的優(yōu)化。
x = "a" + 4 + "c"
會(huì)被編繹成
x = new StringBuffer().append("a").append(4).append("c").toString()
但:
x = “a”;
x = x + 4;
x = x + “c”;
則不會(huì)被優(yōu)化。 可以看出如果在一個(gè)表達(dá)式里面進(jìn)行String的多次+操作會(huì)被優(yōu)化, 而多個(gè)表達(dá)式的+操作不會(huì)被優(yōu)化。
摘自:《Java API Using, Tips And Performance Tuning》
2) Integer、Boolean等wrapper類以及BigInteger、BigDecimal是immutable的,所以也有與String類似的地方,不過(guò)沒(méi)有IntegerBuffer之類的東西。不過(guò)Float, Double比較特殊。如
T a1 = 10; //T代指Byte,Integer,Short,Long,Boolean。 注:應(yīng)用了JDK5的AUTOBOXING
T a2 = 10;
if (a1 == a2)
 System.out.println(true);
else
 System.out.println(false);
這時(shí)總是true,和String有點(diǎn)類似

//Float時(shí)
Float i1 =  (float)10.0;
Float i2 =  (float)10.0;
if (i1==i2)
   System.out.println(true);
else
   System.out.println(false);
這時(shí)總是false

//Double時(shí)
Double i1 =  10.0;
Double i2 =  10.0;
if (i1==i2)
   System.out.println(true);
else
   System.out.println(false);
這時(shí)總是false

總之如果比較兩個(gè)Wrapper類的值用equals,以免不必要的麻煩
3) 再看
String s1 = new String(“Hello”);
String s2 = new String(“Hello”);
s1 == s2 = false;
//因?yàn)閚ew的時(shí)候JVM不管heap中有沒(méi)有”Hello”對(duì)象都會(huì)產(chǎn)生一個(gè)新的”Hello”對(duì)象
String s3 = “Hello”; //重新創(chuàng)建對(duì)象”Hello”, 并令s3指向?qū)ο蟆盚ello”
s3 == s1 = false; //不同對(duì)象當(dāng)然false
String s4 = “Hello”;
s3 == s4 = true;  //故伎重演,jvm清楚的知道哪些用了new,哪些沒(méi)用new

3. 方法的參數(shù)傳遞中都是以reference傳遞,而primitive傳遞的是副本,但如果傳遞的是Integer、Boolean等wrapper類和String類的Object則是以immutable方式傳遞。示例:
import java.awt.Point;
class HelloWorld
{
  public static void modifyPoint(Point pt, String j, int k, Integer m, Boolean b)
  {
    pt.setLocation(5,5);                                     
    j = "15";
    k = 25;
    m = 35;
    b = true;
    System.out.println("During modifyPoint " + "pt = " + pt +
                       " and j = " + j+ " and k = "+ k+
                       " and m = "+ m+ " and b = "+ b);
  }

  public static void main(String args[])
  {
    Point p = new Point(0,0);                                
    String i = "10";
    int k = 20;
    Integer m = 30;
    Boolean b = false;
    System.out.println("Before modifyPoint " + "p = " + p +
                       " and i = " + i+ " and k = "+ k+
                       " and m = "+ m+ " and b = "+ b);
    modifyPoint(p, i, k, m, b);                                       
    System.out.println("After modifyPoint " + "p = " + p +
                       " and i = " + i+ " and k = "+ k+
                       " and m = "+ m+ " and b = "+ b);
  }
}
輸出結(jié)果:
Before modifyPoint p = java.awt.Point[x=0,y=0] and i = 10 and k = 20 and m = 30 and b = false
During modifyPoint pt = java.awt.Point[x=5,y=5] and j = 15 and k = 25 and m = 35 and b = true
After modifyPoint p = java.awt.Point[x=5,y=5] and i = 10 and k = 20 and m = 30 and b = false
4. final作用于基本類型變量則該變量為恒常量;final作用于對(duì)象類型變量則該對(duì)象reference為恒量;final作用于方法則該方法不能被覆蓋;final作用于class則該class不能被繼承。
final使得被修飾的變量"不變",但是由于對(duì)象型變量的本質(zhì)是“引用”,使得“不變”也有了兩種含義:引用本身的不變,和引用指向的對(duì)象不變。

引用本身的不變:
final StringBuffer a=new StringBuffer("immutable");
final StringBuffer b=new StringBuffer("not immutable");
a=b;//編譯期錯(cuò)誤

引用指向的對(duì)象不變:
final StringBuffer a=new StringBuffer("immutable");
a.append(" broken!"); //編譯通過(guò)

可見(jiàn),final只對(duì)引用的“值”(也即它所指向的那個(gè)對(duì)象的內(nèi)存地址)有效,它迫使引用只能指向初始指向的那個(gè)對(duì)象,改變它的指向會(huì)導(dǎo)致編譯期錯(cuò)誤。至于它所指向的對(duì)象的變化,final是不負(fù)責(zé)的。這很類似==操作符:==操作符只負(fù)責(zé)引用的“值”相等,至于這個(gè)地址所指向的對(duì)象內(nèi)容是否相等,==操作符是不管的。

理解final問(wèn)題有很重要的含義。許多程序漏洞都基于此----final只能保證引用永遠(yuǎn)指向固定對(duì)象,不能保證那個(gè)對(duì)象的狀態(tài)不變。在多線程的操作中,一個(gè)對(duì)象會(huì)被多個(gè)線程共享或修改,一個(gè)線程對(duì)對(duì)象無(wú)意識(shí)的修改可能會(huì)導(dǎo)致另一個(gè)使用此對(duì)象的線程崩潰。一個(gè)錯(cuò)誤的解決方法就是在此對(duì)象新建的時(shí)候把它聲明為final,意圖使得它“永遠(yuǎn)不變”。其實(shí)那是徒勞的。
5. 怎樣初始化
本問(wèn)題討論變量的初始化,所以先來(lái)看一下Java中有哪些種類的變量。
1). 類的屬性,或者叫值域
2). 方法里的局部變量
3). 方法的參數(shù)

對(duì)于第一種變量,Java虛擬機(jī)會(huì)自動(dòng)進(jìn)行初始化。如果給出了初始值,則初始化為該初始值。如果沒(méi)有給出,則把它初始化為該類型變量的默認(rèn)初始值。

primitive類型默認(rèn)值
boolean: false
char: '\u0000'  對(duì)于未初始化的char c, c == ‘\u0000’ = true
byte: 0
short: 0
int: 0
long: 0
float: 0.0
double: 0.0
object reference: null
array: null
注意數(shù)組本身也是對(duì)象,所以沒(méi)有初始化的數(shù)組引用在自動(dòng)初始化后其值也是null。

對(duì)于兩種不同的類屬性,static屬性與instance屬性,初始化的時(shí)機(jī)是不同的。instance屬性在創(chuàng)建實(shí)例的時(shí)候初始化,static屬性在類加載,也就是第一次用到這個(gè)類的時(shí)候初始化,對(duì)于后來(lái)的實(shí)例的創(chuàng)建,不再次進(jìn)行初始化。

對(duì)于第二種變量,必須明確地進(jìn)行初始化。如果再?zèng)]有初始化之前就試圖使用它,編譯器會(huì)抗議。如果初始化的語(yǔ)句在try塊中或if塊中,也必須要讓它在第一次使用前一定能夠得到賦值。也就是說(shuō),把初始化語(yǔ)句放在只有if塊的條件判斷語(yǔ)句中編譯器也會(huì)抗議,因?yàn)閳?zhí)行的時(shí)候可能不符合if后面的判斷條件,如此一來(lái)初始化語(yǔ)句就不會(huì)被執(zhí)行了,這就違反了局部變量使用前必須初始化的規(guī)定。但如果在else塊中也有初始化語(yǔ)句,就可以通過(guò)編譯,因?yàn)闊o(wú)論如何,總有至少一條初始化語(yǔ)句會(huì)被執(zhí)行,不會(huì)發(fā)生使用前未被初始化的事情。對(duì)于try-catch也是一樣,如果只有在try塊里才有初始化語(yǔ)句,編譯部通過(guò)。如果在 catch或finally里也有,則可以通過(guò)編譯??傊WC局部變量在使用之前一定被初始化了。所以,一個(gè)好的做法是在聲明他們的時(shí)候就初始化他們,如果不知道要出事化成什么值好,就用上面的默認(rèn)值吧!

其實(shí)第三種變量和第二種本質(zhì)上是一樣的,都是方法中的局部變量。只不過(guò)作為參數(shù),肯定是被初始化過(guò)的,傳入的值就是初始值,所以不需要初始化。
6. 盡量使用多態(tài)(polymorphism)特性而不是instanceof
7. 一旦不需要對(duì)象,盡量顯式的使之為null
8. 對(duì)象之間的”=”賦值操作乃是賦值的reference, 即左邊的對(duì)象也指向右邊的對(duì)象,只是該reference多了一個(gè)別名而已。
9. “==”和equals()的區(qū)別
==操作符專門用來(lái)比較變量的值是否相等。比較好理解的一點(diǎn)是:
int a=10;
int b=10;
則a==b將是true。
但不好理解的地方是:
String a=new String("foo");
String b=new String("foo");
則a==b將返回false。

根據(jù)前一帖說(shuō)過(guò),對(duì)象變量其實(shí)是一個(gè)引用,它們的值是指向?qū)ο笏诘膬?nèi)存地址,而不是對(duì)象本身。a和b都使用了new操作符,意味著將在內(nèi)存中產(chǎn)生兩個(gè)內(nèi)容為"foo"的字符串,既然是“兩個(gè)”,它們自然位于不同的內(nèi)存地址。a和b的值其實(shí)是兩個(gè)不同的內(nèi)存地址的值,所以使用"=="操作符,結(jié)果會(huì)是 false。誠(chéng)然,a和b所指的對(duì)象,它們的內(nèi)容都是"foo",應(yīng)該是“相等”,但是==操作符并不涉及到對(duì)象內(nèi)容的比較。
對(duì)象內(nèi)容的比較,正是equals方法做的事。

看一下Object對(duì)象的equals方法是如何實(shí)現(xiàn)的:
boolean equals(Object o){

return this==o;

}
Object 對(duì)象默認(rèn)使用了==操作符。所以如果你自創(chuàng)的類沒(méi)有覆蓋equals方法,那你的類使用equals和使用==會(huì)得到同樣的結(jié)果。同樣也可以看出, Object的equals方法沒(méi)有達(dá)到equals方法應(yīng)該達(dá)到的目標(biāo):比較兩個(gè)對(duì)象內(nèi)容是否相等。因?yàn)榇鸢笐?yīng)該由類的創(chuàng)建者決定,所以O(shè)bject把這個(gè)任務(wù)留給了類的創(chuàng)建者。

看一下一個(gè)極端的類:
Class Monster{
private String content;
...
boolean equals(Object another){ return true;}

}
我覆蓋了equals方法。這個(gè)實(shí)現(xiàn)會(huì)導(dǎo)致無(wú)論Monster實(shí)例內(nèi)容如何,它們之間的比較永遠(yuǎn)返回true。

所以當(dāng)你是用equals方法判斷對(duì)象的內(nèi)容是否相等,請(qǐng)不要想當(dāng)然。因?yàn)榭赡苣阏J(rèn)為相等,而這個(gè)類的作者不這樣認(rèn)為,而類的equals方法的實(shí)現(xiàn)是由他掌握的。如果你需要使用equals方法,或者使用任何基于散列碼的集合(HashSet,HashMap,HashTable),請(qǐng)察看一下java doc以確認(rèn)這個(gè)類的equals邏輯是如何實(shí)現(xiàn)的。
10. 不要依賴equals()的缺省實(shí)現(xiàn)
11. 一個(gè)equals()的實(shí)現(xiàn)模版
class Golfball
{
  private String brand;
  private String make;
  private int compression;

  public boolean equals(Object obj)
  {

    if (this == obj)
      return true;

    if (obj != null && getClass() == obj.getClass())
    {
      Golfball gb = (Golfball)obj;  //Classes are equal, downcast.
      if (brand.equals(gb.brand()) &&  //Compare attributes.
          make.equals(gb.make()) &&
          compression == gb.compression())
      {
        return true;
      }
    }
    return false;
  }
}
注意getClass() == obj.getClass()的限制,如果判斷必須相等則無(wú)法比較基類和子類是否相等,完全不同的類不用考慮,完全沒(méi)有可比性,除了特殊需要或很糟糕的程序。
12. 實(shí)現(xiàn)equals()應(yīng)優(yōu)先考慮使用getClass()
13. 如果某個(gè)基類我們自己實(shí)現(xiàn)了equals(),在它的子類中要覆蓋此方法,最好調(diào)用super.equals()喚起base class的相關(guān)行為,然后再實(shí)現(xiàn)子類域的比較。
Example:
  public boolean equals(Object obj)
  {
    if (this == obj)                                          //1
      return true;

    if (obj != null && getClass() == obj.getClass() &&        //2
        super.equals(obj))                                    //3
    {
      MyGolfball gb = (MyGolfball)obj;  //Classes equal, downcast.
      if (ballConstruction == gb.construction())  //Compare attrs.
        return true;
    }
    return false;
  }
14. 如果要在base class與derived class之間應(yīng)運(yùn)equals(),可以考慮instanceof來(lái)代替getClass()。對(duì)此論題的詳細(xì)討論參見(jiàn):Practical Java, Practice 14
15. instanceof什么東西?
instanceof是Java的一個(gè)二元操作符,和==,>,<是同一類東東。由于它是由字母組成的,所以也是Java的保留關(guān)鍵字。它的作用是測(cè)試它左邊的對(duì)象是否是它右邊的類的實(shí)例,返回boolean類型的數(shù)據(jù)。舉個(gè)例子:

String s = "I AM an Object!";
boolean isObject = s instanceof Object;

我們聲明了一個(gè)String對(duì)象引用,指向一個(gè)String對(duì)象,然后用instancof來(lái)測(cè)試它所指向的對(duì)象是否是Object類的一個(gè)實(shí)例,顯然,這是真的,所以返回true,也就是isObject的值為True。
instanceof有一些用處。比如我們寫了一個(gè)處理賬單的系統(tǒng),其中有這樣三個(gè)類:

public class Bill {//省略細(xì)節(jié)}
public class PhoneBill extends Bill {//省略細(xì)節(jié)}
public class GasBill extends Bill {//省略細(xì)節(jié)}

在處理程序里有一個(gè)方法,接受一個(gè)Bill類型的對(duì)象,計(jì)算金額。假設(shè)兩種賬單計(jì)算方法不同,而傳入的Bill對(duì)象可能是兩種中的任何一種,所以要用instanceof來(lái)判斷:

public double calculate(Bill bill) {
if (bill instanceof PhoneBill) {
//計(jì)算電話賬單
}
if (bill instanceof GasBill) {
//計(jì)算燃?xì)赓~單
}
...
}
這樣就可以用一個(gè)方法處理兩種子類。

然而,這種做法通常被認(rèn)為是沒(méi)有好好利用面向?qū)ο笾械亩鄳B(tài)性。其實(shí)上面的功能要求用方法重載完全可以實(shí)現(xiàn),這是面向?qū)ο笞兂蓱?yīng)有的做法,避免回到結(jié)構(gòu)化編程模式。只要提供兩個(gè)名字和返回值都相同,接受參數(shù)類型不同的方法就可以了:

public double calculate(PhoneBill bill) {
//計(jì)算電話賬單
}

public double calculate(GasBill bill) {
//計(jì)算燃?xì)赓~單
}

所以,使用instanceof在絕大多數(shù)情況下并不是推薦的做法,應(yīng)當(dāng)好好利用多態(tài)。
16. 認(rèn)真對(duì)待異常。
1).在方法體用throws子句拋出異常時(shí)盡量包括所有出現(xiàn)的異常,而不是僅僅拋出base exception.
2).在super class中定義的方法拋出某個(gè)異常,如果在deriver class中要override該方法,那么overriding method必須:
a. 不拋出任何異常
b. 拋出和super class 中同樣的異常
c. 拋出和super class 中異常的deriver class
如果super class中定義的方法沒(méi)有拋出異常,但deriver class中的override的方法會(huì)產(chǎn)生異常,必須自己內(nèi)部解決
 3).好好利用finally功能。一般只要有finally,它總是會(huì)被執(zhí)行,除非在try中用System.exit(0)或者在try塊執(zhí)行期間強(qiáng)行拔掉電源。finally被執(zhí)行有三種情況:
a. 拋出異常
b. try正常結(jié)束
c. 在try中執(zhí)行了return, break, continue而引起離開(kāi)try的操作
尤其注意c.如果方法中在try塊return 1,而在finally塊return 2,則最終永遠(yuǎn)是2,因此盡量避免在try中使用return, break, continue,要么確保在finally中不會(huì)改變返回值
 4).不要在循環(huán)體中使用try,因?yàn)樵跓o(wú)JIT的JVM中將大大降低性能,而且這也是良好的編程習(xí)慣
 5).不要將異常用于控制流程,而是僅僅用于會(huì)發(fā)生錯(cuò)誤的地方
 6).不要每逢出錯(cuò)就使用異常,盡量使用傳統(tǒng)的方法判斷變量的有效性
17. 關(guān)于不可變類(Immutable class),如String、Byte、Integer、Short、Long、Float、Double、BigInteger、BigDecimal等,它們之所以能將同一值自動(dòng)地指向同一引用,實(shí)際上是它們實(shí)現(xiàn)了靜態(tài)工廠方法。



]]>
derby(cloudscape)數(shù)據(jù)庫(kù)初探(二)—eclipse中對(duì)derby的訪問(wèn)http://www.aygfsteel.com/gufen/archive/2005/09/25/13991.html落花飛雪落花飛雪Sun, 25 Sep 2005 07:21:00 GMThttp://www.aygfsteel.com/gufen/archive/2005/09/25/13991.htmlhttp://www.aygfsteel.com/gufen/comments/13991.htmlhttp://www.aygfsteel.com/gufen/archive/2005/09/25/13991.html#Feedback3http://www.aygfsteel.com/gufen/comments/commentRss/13991.htmlhttp://www.aygfsteel.com/gufen/services/trackbacks/13991.html       在(一)中提到以嵌入式引擎作為db不是很清楚其工作方式,后來(lái)考慮了下大概就是個(gè)強(qiáng)大的Access數(shù)據(jù)庫(kù),這種方式下我覺(jué)得將它作為Access數(shù)據(jù)庫(kù)來(lái)進(jìn)行理解比較直觀些。

目前我就用了eclipse下訪問(wèn)derby的3個(gè)插件:

1)        ibm和apache的兩個(gè)插件一起使用,安裝后在java項(xiàng)目點(diǎn)擊右鍵后出現(xiàn)“Apache Derby”,里面有一個(gè)菜單“Add Apache Derby nature”,點(diǎn)擊后將出現(xiàn)start、ij、sysinfo工具,這個(gè)插件就這些東西。

2)       用Quantum或dbedit插件訪問(wèn)derby.dbedit插件比較強(qiáng)大些,可以可視的進(jìn)行表的alert操作,好像沒(méi)有proc,view的顯示界面。Quantum有proc,view的顯示界面,但是沒(méi)法可視進(jìn)行添加表功能。兩個(gè)都有可視sql edit界面。我沒(méi)搞定如何用derby的jdbc進(jìn)行對(duì)數(shù)據(jù)庫(kù)的訪問(wèn),只能用db2的jdbc訪問(wèn),url為:jdbc:db2://localhost:1527/"C:\IBM\Cloudscape_10.0\demo\databases\toursDB"



]]>
derby(cloudscape)數(shù)據(jù)庫(kù)初探(一)http://www.aygfsteel.com/gufen/archive/2005/09/25/13990.html落花飛雪落花飛雪Sun, 25 Sep 2005 07:20:00 GMThttp://www.aygfsteel.com/gufen/archive/2005/09/25/13990.htmlhttp://www.aygfsteel.com/gufen/comments/13990.htmlhttp://www.aygfsteel.com/gufen/archive/2005/09/25/13990.html#Feedback0http://www.aygfsteel.com/gufen/comments/commentRss/13990.htmlhttp://www.aygfsteel.com/gufen/services/trackbacks/13990.htmlApache一方目前版本是Derby 10.1.0.0 alpha (Apr 28, 2005 / SVN 165185)。由于alpha版,而且Derby 10.0.2.2 (Apr 28, 2005 / SVN 165169)版本的數(shù)據(jù)庫(kù)提供的附加工具及少,所以我是去IBM網(wǎng)站下載的數(shù)據(jù)庫(kù)。
IBM網(wǎng)站目前版本是V10.0.2.0  Build: 30301,提供3種類型的下載,有installer的linux,win32和沒(méi)有installer一個(gè)單一的zip包文件。win32中包括jdk1.4,考慮到我的機(jī)器已經(jīng)被迫安裝了n個(gè)jdk,故此我下載了單一zip包的cloudscape。IBM下載地址為:http://www-128.ibm.com/developerworks/cn/db2/library/techarticles/dm-0408cline/index.html,需要以自己的mail作為id注冊(cè)一個(gè)用戶才能下載。
2.         下載后運(yùn)行java –jar 10.0-IBM-Cloudscape.jar,出現(xiàn)安裝界面,在這里需要指定安裝目錄,需要注意的是安裝目錄盡量不要帶有空格。
3.         安裝完后需要進(jìn)行一些環(huán)境變量的設(shè)置,請(qǐng)根據(jù)自己的實(shí)際情況增加以下環(huán)境變量:
數(shù)據(jù)庫(kù)安裝目錄環(huán)境變量:
CLOUDSCAPE_INSTALL= D:\IBM\Cloudscape_10.0
classpath中增加:
.;%CLOUDSCAPE_INSTALL%\lib\derby.jar;%CLOUDSCAPE_INSTALL%\lib\derbynet.jar;%CLOUDSCAPE_INSTALL%\lib\derbytools.jar;%CLOUDSCAPE_INSTALL%\lib\db2jcc.jar;%CLOUDSCAPE_INSTALL%\lib\db2jcc_license_c.jar
path中增加:
%CLOUDSCAPE_INSTALL%\frameworks\NetworkServer\bin
4.         現(xiàn)在就可以對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作。該數(shù)據(jù)庫(kù)提供兩種模式的數(shù)據(jù)庫(kù)引擎:1. 服務(wù)器架構(gòu)中充當(dāng)客戶機(jī)/服務(wù)器的引擎。2. 作為可嵌入類庫(kù)的數(shù)據(jù)庫(kù)引擎。在c/s引擎應(yīng)該比較了解??汕度腩悗?kù)的數(shù)據(jù)庫(kù)引擎就是和java程序運(yùn)行在同一JVM中,不需要啟動(dòng)數(shù)據(jù)庫(kù),不需要對(duì)數(shù)據(jù)庫(kù)進(jìn)行管理(對(duì)這個(gè)我也知道個(gè)大概,呵呵)。
1.C/S模式下的數(shù)據(jù)庫(kù)訪問(wèn):
打開(kāi)dos界面,敲入startNetworkServer啟動(dòng)數(shù)據(jù)庫(kù),再打開(kāi)一個(gè)dos界面敲ij以進(jìn)行數(shù)據(jù)庫(kù)管理。
在D:\IBM\Cloudscape_10.0\demo\databases下有一toursDB的demo數(shù)據(jù)庫(kù),我們要連至該數(shù)據(jù)庫(kù)我們可以在ij下敲入:connect 'jdbc:derby:net://localhost:1527/"D:\IBM\Cloudscape_10.0\demo\databases\toursDB"'
例如以下我是對(duì)數(shù)據(jù)庫(kù)的一些簡(jiǎn)單操作:
--連接數(shù)據(jù)庫(kù):
ij> connect 'jdbc:derby:net://localhost:1527/"D:\IBM\Cloudscape_10.0\demo\databases\toursDB"';
--創(chuàng)建一個(gè)名為abc的表:
ij> create table abc (a int, b int);
0 rows inserted/updated/deleted
--往abc表中插入數(shù)據(jù),沒(méi)into還報(bào)錯(cuò),用sybase用習(xí)慣了。
ij> insert abc values(1,2);
ERROR 42X01: DB2 SQL error: SQLCODE: -1, SQLSTATE: 42X01, SQLERRMC: Encountered "abc" at line 1, column 8?42X0(?代表一個(gè)怪字符,spaces上發(fā)布的時(shí)候提示“此空間暫時(shí)不可用”,沒(méi)辦法只好用?代替啦,發(fā)現(xiàn)問(wèn)題浪費(fèi)了我十幾分鐘時(shí)間,TNND)
--這次數(shù)據(jù)進(jìn)去了
ij> insert into abc values(1,2);
1 row inserted/updated/deleted
--察看剛才插入的數(shù)據(jù)
ij> select * from abc;
A          |B
-----------------------
1          |2
1 row selected
--斷開(kāi)數(shù)據(jù)庫(kù)連接,沒(méi)有任何信息輸出
ij> disconnect;
--退出ij
ij> exit;
注意命令結(jié)束符是分號(hào)“;”
如果要停止數(shù)據(jù)庫(kù)在dos中敲入stopnetworkserver即可。
2.可嵌入類庫(kù)模式下對(duì)DB的訪問(wèn)(該模式下不需要啟動(dòng)數(shù)據(jù)庫(kù),且ij中只能有一個(gè)連接操作數(shù)據(jù)庫(kù))
我的toursDB數(shù)據(jù)庫(kù)目錄為C:\IBM\Cloudscape_10.0\demo\databases下,如果我們DOS界面所在的目錄已經(jīng)在在該目錄,則進(jìn)入ij后直接敲入“connect 'jdbc:derby:toursDB';”就可以連接至數(shù)據(jù)庫(kù),否則得指定數(shù)據(jù)庫(kù)所在路徑“connect 'jdbc:derby:C:\IBM\Cloudscape_10.0\demo\databases\toursDB';”。下面是我對(duì)數(shù)據(jù)庫(kù)的一些訪問(wèn):
ij> connect 'jdbc:derby:toursDB';
ij> select * from cities;
CITY_ID    |CITY_NAME               |COUNTRY                   |AIRPORT                   |LANGUAGE
       |COU&
----------------------------------------------------------------------------------------------------
------------
1          |Amsterdam               |Netherlands               |AMS                       |Dutch
       |NL
……………………………等等
87 rows selected
ij> disconnect;
ij> exit;
C:\IBM\Cloudscape_10.0\demo\databases>
其中cities是toursDB數(shù)據(jù)庫(kù)自帶的一個(gè)表,其它的表還有airlines, countries,flightavailability,flights,flights_history,maps。
關(guān)于數(shù)據(jù)庫(kù)的一些操作命令可在ij下敲入help;進(jìn)行察看,詳細(xì)的幫助信息在D:\IBM\Cloudscape_10.0\doc\pdf中,IBM的developerWorks下的DB2有很多介紹cloudscape相關(guān)技術(shù)的文章,網(wǎng)址:http://www-128.ibm.com/developerworks/cn/index.html。 還有IBM的在線幫助手冊(cè)有3本是中文的,網(wǎng)址:http://www.elink.ibmlink.ibm.com/public/applications/publications/cgibin/pbi.cgi?CTY=US&FNC=ICL,進(jìn)去后選擇cloudscape。

]]>
MyEclipse中配置Weblogic(轉(zhuǎn))http://www.aygfsteel.com/gufen/archive/2005/09/25/13989.html落花飛雪落花飛雪Sun, 25 Sep 2005 07:19:00 GMThttp://www.aygfsteel.com/gufen/archive/2005/09/25/13989.htmlhttp://www.aygfsteel.com/gufen/comments/13989.htmlhttp://www.aygfsteel.com/gufen/archive/2005/09/25/13989.html#Feedback2http://www.aygfsteel.com/gufen/comments/commentRss/13989.htmlhttp://www.aygfsteel.com/gufen/services/trackbacks/13989.html轉(zhuǎn)自http://dev2dev.bea.com.cn/bbs,作者:newwei

1)選擇菜單Window->Preferences->MyEclipse->Application Servers->Weblogic 8,配置項(xiàng)目如下:
BEA home directory: 選擇Bea的安裝目錄
Weblogic installation directory:現(xiàn)在BEA下面的weblogic81目錄
Admin username:輸入上面在配置過(guò)程中設(shè)的用戶名
Admin password:輸入剛才設(shè)的密碼
Execution domain root:選擇BEA下user_projects\domains目錄下上面第一步創(chuàng)建的目錄
Execution domain name:輸入上面那個(gè)目錄的名稱
Execution server name:輸入上一步的那個(gè)Congfiguration Name
Hostname:PortNumber:輸入IP地址和監(jiān)聽(tīng)的端口
Security policy file:輸入BEA安裝目錄下的\weblogic81\server\lib\weblogic.policy
(2)在Weblogic 8下面配置JDK,在WLS JDK name那里選擇新建,彈出的對(duì)話框中選擇BEA下面的JDK安裝路徑,輸入一個(gè)名字確定就可以;在Optional Java VM arguments對(duì)話框里面輸入-ms64m -mx64m -Djava.library.path="D:/BEA/weblogic81/server/bin" -Dweblogic.management.discover=false -Dweblogic.ProductionModeEnabled=false
(3在Weblogic 8下面配置Paths,加入BEA安裝路徑下/weblogic81/server/lib中的webservices.jar和weblogic.jar兩個(gè)包。如果需要其他的包,也在這里加入。

PS:我使用的環(huán)境是Eclipse 3.0.3和MyEclipse3.8.4,操作系統(tǒng)是Windows 2000



]]>
Tomcat下JSP、Servlet和JavaBean環(huán)境的配置 http://www.aygfsteel.com/gufen/archive/2005/09/25/13988.html落花飛雪落花飛雪Sun, 25 Sep 2005 07:17:00 GMThttp://www.aygfsteel.com/gufen/archive/2005/09/25/13988.htmlhttp://www.aygfsteel.com/gufen/comments/13988.htmlhttp://www.aygfsteel.com/gufen/archive/2005/09/25/13988.html#Feedback12http://www.aygfsteel.com/gufen/comments/commentRss/13988.htmlhttp://www.aygfsteel.com/gufen/services/trackbacks/13988.html版本:Tomcat 5.5.9,Win2000

1. 安裝jdk5.0, jre5.0,之后設(shè)置環(huán)境變量
增加如下系統(tǒng)環(huán)境變量(注:jdk安裝目錄D:\jdk15)。
java_home= D:\jdk15
classpath=.;%java_home%\lib\tools.jar;%java_home%\lib\dt.jar;
path系統(tǒng)變量中增加%java_home%\bin;(盡量加在最前面)
2. 安裝Tomcat
    一路“下一步”安裝完成,途中有確認(rèn)jre路徑界面需要注意。啟動(dòng)Tomcat服務(wù)后在游覽器中敲入
http://127.0.0.1:8080/或者http://localhost:8080/后出現(xiàn)傳說(shuō)中丑陋的三腳Cat即安裝成功。
  增加如下系統(tǒng)環(huán)境變量
  CATALINA_HOME= C:\Program Files\Apache Software Foundation\Tomcat 5.5(我是默認(rèn)安裝)
classpath中增加以下內(nèi)容
%CATALINA_HOME%\common\lib\servlet-api.jar;%CATALINA_HOME%\common\lib\jasper-runtime.jar;%CATALINA_HOME%\common\lib\jsp-api.jar;
TOMCAT的一些JAVA CLASS都在%CATALINA_HOME%\common\lib,如果jsp,bean編譯不過(guò)去,看看錯(cuò)誤如果有not found class之類的,就去%CATALINA_HOME%\common\lib下找,找到后加至classpath中就可以了。
3. 發(fā)布第一個(gè)jsp:HelloWord
Tomcat所有的程序均發(fā)布在D:\Program Files\Apache Software Foundation\Tomcat 5.5\webapps路徑的各個(gè)目錄里,在2中看見(jiàn)的丑陋貓就是ROOT下的index.jsp。
在webapps下建立一個(gè)目錄mytest,然后拷貝ROOT下的WEB-INF目錄到mytest目錄,這里面是一些配置文件。之后在mytest中建立文件HelloWorld.jsp,文件內(nèi)容為:
<%@ page language="java" %>
<html>
 <head><title></title></head>
 <body>
  <center>
   <%! String str = new String("HelloWorld!"); %>
   <font color="blue"><%= str %> </font><br>
  </center>
 </body>
</html>
保存后在游覽器中輸入
http://127.0.0.1:8080/mytest/HelloWorld.jsp, 如果沒(méi)有意外的話應(yīng)該執(zhí)行成功,表示已正式進(jìn)入jsp世界,不行重起tomcat。
4. 發(fā)布第一個(gè)servlet
 在mytest\WEB-INF下新建classes目錄,然后在classes下新建目錄test,test目錄中新建文件HelloServlet.java。內(nèi)容為:
package test;
//因?yàn)槲覀兊陌鼮閠est所以以上一句必須有,如果直接是在classes下新建//HelloServlet.java,則不需要聲明包。
import java.io.*;
import java.util.*;
//導(dǎo)入servlet包
import javax.servlet.*;
public class HelloServlet extends GenericServlet

 public void init(ServletConfig config)throws ServletException
 {
  super.init(config);
  //調(diào)用父類的初始化方法;也可以加入自己需要的初始化代碼。
 } 
 public void destroy(){
  //destroy方法中加入一些做最后清理工作的代碼;

 public String getServletInfo(){
  return "This servlet is a simple Servlet's example.";
  //返回此servlet的信息 ;
 } 
 public void service(ServletRequest req,ServletResponse res)
   throws ServletException,IOException
 {  //service是最主要的方法,提供服務(wù)
  //獲得服務(wù)器當(dāng)前時(shí)間。
  Date today=new Date();

  //獲得響應(yīng)用戶請(qǐng)求的輸出流,以反饋執(zhí)行結(jié)果;
  ServletOutputStream out=res.getOutputStream();

  //通過(guò)輸出流向客戶端寫回了一個(gè)HTML文件;
  out.println("<html><head><title>HelloServlet.java</title></head><body>");
  out.println("Hello,this is my first test.+<BR>");
  out.println("Today is "+today.toString()+"<BR>");
  out.println(getServletInfo()+"<BR>");
 }
}

 之后編譯HelloServlet.java ,在命令行中敲入javac HelloServlet.java。在游覽器中查看該Servlet之前需要改動(dòng)mytest\WEB-INF\web.xml文件,建立HelloServlet的映射。將以下代碼拷貝至web.xml文件。
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>test.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/servlet/HelloServlet</url-pattern>
</servlet-mapping>
保存后在游覽器地址欄中敲入
http://localhost:8080/mytest/servlet/HelloServlet后出現(xiàn)Hello,this is my first test.+等字樣表示已經(jīng)進(jìn)入Servlet世界。
注意我們將HelloServlet映射為/servlet/HelloServlet所以在
http://localhost:8080/mytest后敲入的是/servlet/HelloServlet;如果我們直接映射為/HelloServlet,即改為<url-pattern> /HelloServlet</url-pattern>,則在游覽器地址欄中敲入的應(yīng)該是http://localhost:8080/mytest/HelloServlet
5. 發(fā)布第一個(gè)bean(這個(gè)例子應(yīng)用了jsp頁(yè)面)
1) 先在C:\Program Files\Apache Software Foundation\Tomcat 5.5\webapps\mytest下建立一個(gè)htm文檔transPara.htm
內(nèi)容為:
<html>
 <head>
  <title>transPara.htm</title>
 </head>
<body>
 <form method="POST" action="acceptPara.jsp">
    <p align="center">
  姓 名:<input type="text" name="name" size="20"><br>
    年 齡:&nbsp;&nbsp;&nbsp; <input type="text" name="age" size="15"><br>
    性 別:&nbsp;&nbsp;&nbsp;
   <input type="radio" value="male" checked name="sex">
    男&nbsp;&nbsp;&nbsp;&nbsp; 
     <input type="radio" name="sex" value="female">女</p>
    <p align="center">
   <input type="submit" value="submit" name="submit">
     <input type="reset" value="reset" name="reset"></p>
 </form>
</body>
</html>
2) 在C:\Program Files\Apache Software Foundation\Tomcat 5.5\webapps\mytest下建立一個(gè)jsp文檔acceptPara.jsp
內(nèi)容為:
<html>
<
%@ page import="test.acceptPara" contentType="text/html;charset=gb2312"%>
<jsp:useBean id="atest" class="test.acceptPara"/>
<head><title>acceptPara.jsp</title></head>
<body>
<jsp:setProperty name="atest" property="*"/>
Value of property "name" :
<jsp:getProperty name="atest" property="name"/><br>
Value of property "age" :
<jsp:getProperty name="atest" property="age"/><br>
Value of property "sex" :
<jsp:getProperty name="atest" property="sex"/><br>
Value of property "submit" :
<jsp:getProperty name="atest" property="submit"/><br>
</body>
</html>
3) 在C:\Program Files\Apache Software Foundation\Tomcat 5.5\webapps\mytest\WEB-INF\classes\test下建立bean: acceptPara.java
內(nèi)容為:
package test;

public class acceptPara{
 String name;
 int age;
 String sex;
 String submit;
 
 public void setName(String value){
  name=value;
 } 
 public String getName(){
  return name;
 } 
 public void setAge(int value){
  age=value;
 } 
 public int getAge(){
  return age;
 } 
 public void setSex(String value){
  sex=value;
 } 
 public String getSex(){
  return sex;
 } 
 public void setSubmit(String value){
  submit=value;
 } 
 public String getSubmit(){
  return submit;
 }
 public void acceptPara(){}
}
編譯該bean,之后在游覽器地址欄中敲入
http://localhost:8080/mytest/transPara.htm,我們可以看見(jiàn)有姓名、年齡、性別幾個(gè)表單,輸入各個(gè)項(xiàng)后點(diǎn)擊submit就可以看到我們剛才輸入的結(jié)果,大概返回結(jié)果如下:
Value of property "name" : Joson
Value of property "age" : 23
Value of property "sex" : male
Value of property "submit" : submit



]]>
主站蜘蛛池模板: 琼结县| 咸宁市| 德阳市| 郎溪县| 瑞金市| 新乐市| 诏安县| 武定县| 兴文县| 敦煌市| 岑巩县| 略阳县| 视频| 佳木斯市| 洛阳市| 隆德县| 洛南县| 正宁县| 林芝县| 宾阳县| 宜城市| 双桥区| 永修县| 西青区| 三原县| 台前县| 长宁区| 平利县| 大田县| 华蓥市| 锡林浩特市| 威信县| 饶阳县| 丹江口市| 白山市| 黔西| 临泉县| 扎囊县| 体育| 翼城县| 上饶市|