亚洲熟妇少妇任你躁在线观看无码,国产精品亚洲专区在线观看,亚洲伦理一区二区http://www.tkk7.com/gufen/zh-cnSat, 10 May 2025 19:24:32 GMTSat, 10 May 2025 19:24:32 GMT60MyEclipse+WebSphere通過JNDI連接Sybase簡介http://www.tkk7.com/gufen/archive/2006/06/12/52182.html落花飛雪落花飛雪Mon, 12 Jun 2006 04:57:00 GMThttp://www.tkk7.com/gufen/archive/2006/06/12/52182.htmlhttp://www.tkk7.com/gufen/comments/52182.htmlhttp://www.tkk7.com/gufen/archive/2006/06/12/52182.html#Feedback0http://www.tkk7.com/gufen/comments/commentRss/52182.htmlhttp://www.tkk7.com/gufen/services/trackbacks/52182.html閱讀全文

落花飛雪 2006-06-12 12:57 發表評論
]]>
JDK5.0的11個主要新特征http://www.tkk7.com/gufen/archive/2005/10/15/15567.html落花飛雪落花飛雪Sat, 15 Oct 2005 04:15:00 GMThttp://www.tkk7.com/gufen/archive/2005/10/15/15567.htmlhttp://www.tkk7.com/gufen/comments/15567.htmlhttp://www.tkk7.com/gufen/archive/2005/10/15/15567.html#Feedback1http://www.tkk7.com/gufen/comments/commentRss/15567.htmlhttp://www.tkk7.com/gufen/services/trackbacks/15567.html閱讀全文

落花飛雪 2005-10-15 12:15 發表評論
]]>
Win32下Swt-Designer4.1.1與MyEclipse4.0的破解方法及注冊機http://www.tkk7.com/gufen/archive/2005/09/27/14184.html落花飛雪落花飛雪Tue, 27 Sep 2005 05:05:00 GMThttp://www.tkk7.com/gufen/archive/2005/09/27/14184.htmlhttp://www.tkk7.com/gufen/comments/14184.htmlhttp://www.tkk7.com/gufen/archive/2005/09/27/14184.html#Feedback48http://www.tkk7.com/gufen/comments/commentRss/14184.htmlhttp://www.tkk7.com/gufen/services/trackbacks/14184.htmlWin32Swt-Designer4.1.1破解

環境:win32Eclipse3.1,Designer_v4.1.1

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

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

3.  解壓后在cmd命令中敲入swt.ui.bat,運行后出現以下界面,輸入框中的內容,然后點擊Generate產生序列號和激活碼。

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

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個文件,拷貝到swt.ui.bat所在的目錄。

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

原來是: 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

紅色為修改的地方,然后運行后將Version填入你下載的swt-designer版本號即可產生注冊碼。

4.         將下載的Designer_v4.1.1_for_Eclipse3.1.zip插件安裝到eclipse,如果你不知道如何安裝插件請在google里搜索這方面的文章,應該很多的。我也是這樣走過來的。

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

現在就可以免費使用swt-designer

 

Win32MyEclipse4.0破解

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

以上破解方法僅供個人學習,請支持正版。(形式?)



落花飛雪 2005-09-27 13:05 發表評論
]]>
軟件設計中的原則http://www.tkk7.com/gufen/archive/2005/09/26/14126.html落花飛雪落花飛雪Mon, 26 Sep 2005 09:21:00 GMThttp://www.tkk7.com/gufen/archive/2005/09/26/14126.htmlhttp://www.tkk7.com/gufen/comments/14126.htmlhttp://www.tkk7.com/gufen/archive/2005/09/26/14126.html#Feedback0http://www.tkk7.com/gufen/comments/commentRss/14126.htmlhttp://www.tkk7.com/gufen/services/trackbacks/14126.html     這里說的幾個軟件模式是屬于原則層次一級的,比GoF等軟件設計模式高一層。遵循這些原則可以使我們設計出來的軟件有更好的可復用性和可維護性,同樣GoF等軟件設計模式也是遵循這一原則的。

     下邊的條列只是簡單的介紹,以便忘記了偶爾過來游覽一下,詳細的介紹請參閱:《Java模式》、《UML和模式應用-面向對象分析與設計導論》

1.         GRASP模式

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

1)  專家模式(Expert)

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

通俗點就是:該干嘛干嘛去,別管別人的閑事或者我的職責就是搞這個,別的事不管。

舉個簡單的例子,如果有一個類是專門處理字符串相關的類,那么這個類只能有字符串處理相關的方法,而不要將日期處理的方法加進來。也就是提高軟件高內聚一種原則。

2)  創建者(Creator)

解決方案:將創建一個類A的實例的職責指派給類B的實例,如果下列條件滿足的話:

a)         B聚合了A對象

b)        B包含了A對象

c)        B紀錄了A對象的實例

d)        B要經常使用A對象

e)         A的實例被創建時,B具有要傳遞給A的初始化數據(也就是說B是創建A的實例這項任務的信息專家)

f)         BA對象的創建者

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

通俗點就是:我要用你所以我來創建你,請不要讓別人創建你

這個模式是支持低耦合度原則的一個體現

3)  高聚合度或高內聚(High Cohesion)

解決方案:分配一個職責的時候要保持類的高聚合度

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

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

解決方案:在分配一個職責時要使保持低耦合度。

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

5)  控制者(Controller)

解決方案:將處理系統事件消息的職責分派給代表下列事物的類:

a)         代表整個“系統”的類(虛包控制者)

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

c)        代表真實世界中參與職責(角色控制者)的主動對象類(例,一個人的角色)

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

這是一個控制者角色職責分配的原則,就是哪些控制應該分派給哪個角色。

6)多態

當相關的可選擇的方法或行為隨著類型變化時,將行為的職責-使用多態的操作-分配給那些行為變化的類型

也就是說盡量對抽象層編程,用多態的方法來判斷具體應該使用那個類,而不是用if instanceof 來判斷該類是什么接來執行什么。

7)純虛構

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

例,我們的Sale類的數據要存入數據庫,但是他必須和數據庫接口相連接,如果將接口連接放入Sale類中勢必增加該類的耦合度,所以我們可以虛構一個類來處理與數據庫接口連接的問題。這個類就是我們虛構出來的一個事物。

8)中介者

將職責分配給一個中間對象以便在其他構件或服務之間仲裁,這樣這些構件或服務沒有被直接耦合。這個中間對象(intermediary)在其他構件或服務間創建一個中介者(Indirection)。這個中間對象也就事7)中的純虛構。

9)不要和陌生人講話

分配職責給一個客戶端的直接對象以使它與一個間接對象進行協作,這樣客戶端無需知道這個間接對象。

這個模式-也被叫做(Demeter)準則。

       通俗點就是:只與你直接的朋友們通信

                            不要跟“陌生人”說話

每個軟件單位對其他的單位都只有最少的知識,而且局限于那些與本單位密切相關的軟件單位

2.         其他設計原則

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

一個軟件實體應當對擴展開放,對修改關閉。

意思就是在設計一個模塊的時候,應當使這個模塊在不被修改的前提下被擴展。換言之,應當可以在不修改代碼的情況下改變這個模塊的行為。

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

這個就是盡量用多態的方法編程,也就是GRASP模式中的多態。

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

依賴倒轉原則講的是:要依賴于抽象,不要依賴于具體

就是說我們盡量在抽象層進行控制編程,要針對接口編程,不要針對實現編程。

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

使用多個專門的接口比使用單一的總接口要好。也就是,從一個客戶類的角度來講:一個類對另外一個類的依賴性應當是建立在最小的接口上的。

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

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

6)變與不變的分離
    更擴展一步,就是將不同變化的組件進行隔離.最簡單的例子就是javabean中的存取器。它隔離了不變的接口和變化的內部屬性。這方面體現最好的個人覺得就是eclipse,通過變化的插件,eclipse可以用來實現任何功能。



落花飛雪 2005-09-26 17:21 發表評論
]]>
終于找到個適合自己的地方了。http://www.tkk7.com/gufen/archive/2005/09/25/13995.html落花飛雪落花飛雪Sun, 25 Sep 2005 07:31:00 GMThttp://www.tkk7.com/gufen/archive/2005/09/25/13995.htmlhttp://www.tkk7.com/gufen/comments/13995.htmlhttp://www.tkk7.com/gufen/archive/2005/09/25/13995.html#Feedback0http://www.tkk7.com/gufen/comments/commentRss/13995.htmlhttp://www.tkk7.com/gufen/services/trackbacks/13995.html

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


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


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

許多人都做過這樣的事情,但是,我們到底聲明了什么?回答通常是:一個String,內容是“Hello world!”。這樣模糊的回答通常是概念不清的根源。如果要準確的回答,一半的人大概會回答錯誤。
這個語句聲明的是一個指向對象的引用,名為“s”,可以指向類型為String的任何對象,目前指

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

許多人都做過這樣的事情,但是,我們到底聲明了什么?回答通常是:一個String,內容是“Hello world!”。這樣模糊的回答通常是概念不清的根源。如果要準確的回答,一半的人大概會回答錯誤。
這個語句聲明的是一個指向對象的引用,名為“s”,可以指向類型為String的任何對象,目前指向"Hello world!"這個String類型的對象。這就是真正發生的事情。我們并沒有聲明一個String對象,我們只是聲明了一個只能指向String對象的引用變量。所以,如果在剛才那句語句后面,如果再運行一句:

String string = s;

我們是聲明了另外一個只能指向String對象的引用,名為string,并沒有第二個對象產生,string還是指向原來那個對象,也就是,和s指向同一個對象。
2. String類的特殊性
1) String s1 = “Hello”;  //產生一個String ”Hello”對象,并產生該對象的一個別名s1來引用該對象
String s2 = “Hello”;  //又產生一個別名s2來引用上面的”Hello”對象
s1 == s2 = true;   //由于是同一個對象所以“==”返回為true
s1 = “World”;  //產生一個String ”World”對象, s1的引用不再指向“Hello”而是指向對象”World”
s1 == s2 = false;   //由于不是同一個對象所以“==”返回為false
s1 = “Hello”;  //同上面的String s2 = “Hello”; 現在s1又指向對象”Hello”, 因為JVM會自動根據棧中數據的實際情況來決定是否有必要創建新對象。
s1 == s2 = true;   //由于是同一個對象所以“==”又返回為true了
s1 = s1 + “World”;  //這時又產生一個對象”HelloWord”,s1不再指向”Hello”而是指向”HelloWord”
s1 == s2 = false;  //不是一個對象當然是false拉
s1 = s1+ "a"+"b"+"c"+…;  // String不停的創建對象,影響性能,這種易變的String用StringBuffer會得到更好的性能
StringBuffer s3 = new StringBuffer(“Hello”);
s3.append(“a”); //沒有生成新的對象,而是將s3引用的對象內容改為”Helloa”

//說明: String類用來表示那些創建后就不會再改變的字符串,它是immutable的。而StringBuffer類用來表示內容可變的字符串,并提供了修改底層字符串的方法。
StingBuffer是一個可變的字符串,它可以被更改。同時StringBuffer是Thread safe的, 你可以放心的使用.

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

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

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

總之如果比較兩個Wrapper類的值用equals,以免不必要的麻煩
3) 再看
String s1 = new String(“Hello”);
String s2 = new String(“Hello”);
s1 == s2 = false;
//因為new的時候JVM不管heap中有沒有”Hello”對象都會產生一個新的”Hello”對象
String s3 = “Hello”; //重新創建對象”Hello”, 并令s3指向對象”Hello”
s3 == s1 = false; //不同對象當然false
String s4 = “Hello”;
s3 == s4 = true;  //故伎重演,jvm清楚的知道哪些用了new,哪些沒用new

3. 方法的參數傳遞中都是以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);
  }
}
輸出結果:
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作用于對象類型變量則該對象reference為恒量;final作用于方法則該方法不能被覆蓋;final作用于class則該class不能被繼承。
final使得被修飾的變量"不變",但是由于對象型變量的本質是“引用”,使得“不變”也有了兩種含義:引用本身的不變,和引用指向的對象不變。

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

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

可見,final只對引用的“值”(也即它所指向的那個對象的內存地址)有效,它迫使引用只能指向初始指向的那個對象,改變它的指向會導致編譯期錯誤。至于它所指向的對象的變化,final是不負責的。這很類似==操作符:==操作符只負責引用的“值”相等,至于這個地址所指向的對象內容是否相等,==操作符是不管的。

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

對于第一種變量,Java虛擬機會自動進行初始化。如果給出了初始值,則初始化為該初始值。如果沒有給出,則把它初始化為該類型變量的默認初始值。

primitive類型默認值
boolean: false
char: '\u0000'  對于未初始化的char c, c == ‘\u0000’ = true
byte: 0
short: 0
int: 0
long: 0
float: 0.0
double: 0.0
object reference: null
array: null
注意數組本身也是對象,所以沒有初始化的數組引用在自動初始化后其值也是null。

對于兩種不同的類屬性,static屬性與instance屬性,初始化的時機是不同的。instance屬性在創建實例的時候初始化,static屬性在類加載,也就是第一次用到這個類的時候初始化,對于后來的實例的創建,不再次進行初始化。

對于第二種變量,必須明確地進行初始化。如果再沒有初始化之前就試圖使用它,編譯器會抗議。如果初始化的語句在try塊中或if塊中,也必須要讓它在第一次使用前一定能夠得到賦值。也就是說,把初始化語句放在只有if塊的條件判斷語句中編譯器也會抗議,因為執行的時候可能不符合if后面的判斷條件,如此一來初始化語句就不會被執行了,這就違反了局部變量使用前必須初始化的規定。但如果在else塊中也有初始化語句,就可以通過編譯,因為無論如何,總有至少一條初始化語句會被執行,不會發生使用前未被初始化的事情。對于try-catch也是一樣,如果只有在try塊里才有初始化語句,編譯部通過。如果在 catch或finally里也有,則可以通過編譯??傊?,要保證局部變量在使用之前一定被初始化了。所以,一個好的做法是在聲明他們的時候就初始化他們,如果不知道要出事化成什么值好,就用上面的默認值吧!

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

根據前一帖說過,對象變量其實是一個引用,它們的值是指向對象所在的內存地址,而不是對象本身。a和b都使用了new操作符,意味著將在內存中產生兩個內容為"foo"的字符串,既然是“兩個”,它們自然位于不同的內存地址。a和b的值其實是兩個不同的內存地址的值,所以使用"=="操作符,結果會是 false。誠然,a和b所指的對象,它們的內容都是"foo",應該是“相等”,但是==操作符并不涉及到對象內容的比較。
對象內容的比較,正是equals方法做的事。

看一下Object對象的equals方法是如何實現的:
boolean equals(Object o){

return this==o;

}
Object 對象默認使用了==操作符。所以如果你自創的類沒有覆蓋equals方法,那你的類使用equals和使用==會得到同樣的結果。同樣也可以看出, Object的equals方法沒有達到equals方法應該達到的目標:比較兩個對象內容是否相等。因為答案應該由類的創建者決定,所以Object把這個任務留給了類的創建者。

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

}
我覆蓋了equals方法。這個實現會導致無論Monster實例內容如何,它們之間的比較永遠返回true。

所以當你是用equals方法判斷對象的內容是否相等,請不要想當然。因為可能你認為相等,而這個類的作者不這樣認為,而類的equals方法的實現是由他掌握的。如果你需要使用equals方法,或者使用任何基于散列碼的集合(HashSet,HashMap,HashTable),請察看一下java doc以確認這個類的equals邏輯是如何實現的。
10. 不要依賴equals()的缺省實現
11. 一個equals()的實現模版
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()的限制,如果判斷必須相等則無法比較基類和子類是否相等,完全不同的類不用考慮,完全沒有可比性,除了特殊需要或很糟糕的程序。
12. 實現equals()應優先考慮使用getClass()
13. 如果某個基類我們自己實現了equals(),在它的子類中要覆蓋此方法,最好調用super.equals()喚起base class的相關行為,然后再實現子類域的比較。
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之間應運equals(),可以考慮instanceof來代替getClass()。對此論題的詳細討論參見:Practical Java, Practice 14
15. instanceof什么東西?
instanceof是Java的一個二元操作符,和==,>,<是同一類東東。由于它是由字母組成的,所以也是Java的保留關鍵字。它的作用是測試它左邊的對象是否是它右邊的類的實例,返回boolean類型的數據。舉個例子:

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

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

public class Bill {//省略細節}
public class PhoneBill extends Bill {//省略細節}
public class GasBill extends Bill {//省略細節}

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

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

然而,這種做法通常被認為是沒有好好利用面向對象中的多態性。其實上面的功能要求用方法重載完全可以實現,這是面向對象變成應有的做法,避免回到結構化編程模式。只要提供兩個名字和返回值都相同,接受參數類型不同的方法就可以了:

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

public double calculate(GasBill bill) {
//計算燃氣賬單
}

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



落花飛雪 2005-09-25 15:22 發表評論
]]>
derby(cloudscape)數據庫初探(二)—eclipse中對derby的訪問http://www.tkk7.com/gufen/archive/2005/09/25/13991.html落花飛雪落花飛雪Sun, 25 Sep 2005 07:21:00 GMThttp://www.tkk7.com/gufen/archive/2005/09/25/13991.htmlhttp://www.tkk7.com/gufen/comments/13991.htmlhttp://www.tkk7.com/gufen/archive/2005/09/25/13991.html#Feedback3http://www.tkk7.com/gufen/comments/commentRss/13991.htmlhttp://www.tkk7.com/gufen/services/trackbacks/13991.html       在(一)中提到以嵌入式引擎作為db不是很清楚其工作方式,后來考慮了下大概就是個強大的Access數據庫,這種方式下我覺得將它作為Access數據庫來進行理解比較直觀些。

目前我就用了eclipse下訪問derby的3個插件:

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

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



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

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

1)選擇菜單Window->Preferences->MyEclipse->Application Servers->Weblogic 8,配置項目如下:
BEA home directory: 選擇Bea的安裝目錄
Weblogic installation directory:現在BEA下面的weblogic81目錄
Admin username:輸入上面在配置過程中設的用戶名
Admin password:輸入剛才設的密碼
Execution domain root:選擇BEA下user_projects\domains目錄下上面第一步創建的目錄
Execution domain name:輸入上面那個目錄的名稱
Execution server name:輸入上一步的那個Congfiguration Name
Hostname:PortNumber:輸入IP地址和監聽的端口
Security policy file:輸入BEA安裝目錄下的\weblogic81\server\lib\weblogic.policy
(2)在Weblogic 8下面配置JDK,在WLS JDK name那里選擇新建,彈出的對話框中選擇BEA下面的JDK安裝路徑,輸入一個名字確定就可以;在Optional Java VM arguments對話框里面輸入-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兩個包。如果需要其他的包,也在這里加入。

PS:我使用的環境是Eclipse 3.0.3和MyEclipse3.8.4,操作系統是Windows 2000



落花飛雪 2005-09-25 15:19 發表評論
]]>
Tomcat下JSP、Servlet和JavaBean環境的配置 http://www.tkk7.com/gufen/archive/2005/09/25/13988.html落花飛雪落花飛雪Sun, 25 Sep 2005 07:17:00 GMThttp://www.tkk7.com/gufen/archive/2005/09/25/13988.htmlhttp://www.tkk7.com/gufen/comments/13988.htmlhttp://www.tkk7.com/gufen/archive/2005/09/25/13988.html#Feedback12http://www.tkk7.com/gufen/comments/commentRss/13988.htmlhttp://www.tkk7.com/gufen/services/trackbacks/13988.html版本:Tomcat 5.5.9,Win2000

1. 安裝jdk5.0, jre5.0,之后設置環境變量
增加如下系統環境變量(注:jdk安裝目錄D:\jdk15)。
java_home= D:\jdk15
classpath=.;%java_home%\lib\tools.jar;%java_home%\lib\dt.jar;
path系統變量中增加%java_home%\bin;(盡量加在最前面)
2. 安裝Tomcat
    一路“下一步”安裝完成,途中有確認jre路徑界面需要注意。啟動Tomcat服務后在游覽器中敲入
http://127.0.0.1:8080/或者http://localhost:8080/后出現傳說中丑陋的三腳Cat即安裝成功。
  增加如下系統環境變量
  CATALINA_HOME= C:\Program Files\Apache Software Foundation\Tomcat 5.5(我是默認安裝)
classpath中增加以下內容
%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編譯不過去,看看錯誤如果有not found class之類的,就去%CATALINA_HOME%\common\lib下找,找到后加至classpath中就可以了。
3. 發布第一個jsp:HelloWord
Tomcat所有的程序均發布在D:\Program Files\Apache Software Foundation\Tomcat 5.5\webapps路徑的各個目錄里,在2中看見的丑陋貓就是ROOT下的index.jsp。
在webapps下建立一個目錄mytest,然后拷貝ROOT下的WEB-INF目錄到mytest目錄,這里面是一些配置文件。之后在mytest中建立文件HelloWorld.jsp,文件內容為:
<%@ 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, 如果沒有意外的話應該執行成功,表示已正式進入jsp世界,不行重起tomcat。
4. 發布第一個servlet
 在mytest\WEB-INF下新建classes目錄,然后在classes下新建目錄test,test目錄中新建文件HelloServlet.java。內容為:
package test;
//因為我們的包為test所以以上一句必須有,如果直接是在classes下新建//HelloServlet.java,則不需要聲明包。
import java.io.*;
import java.util.*;
//導入servlet包
import javax.servlet.*;
public class HelloServlet extends GenericServlet

 public void init(ServletConfig config)throws ServletException
 {
  super.init(config);
  //調用父類的初始化方法;也可以加入自己需要的初始化代碼。
 } 
 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是最主要的方法,提供服務
  //獲得服務器當前時間。
  Date today=new Date();

  //獲得響應用戶請求的輸出流,以反饋執行結果;
  ServletOutputStream out=res.getOutputStream();

  //通過輸出流向客戶端寫回了一個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之前需要改動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后出現Hello,this is my first test.+等字樣表示已經進入Servlet世界。
注意我們將HelloServlet映射為/servlet/HelloServlet所以在
http://localhost:8080/mytest后敲入的是/servlet/HelloServlet;如果我們直接映射為/HelloServlet,即改為<url-pattern> /HelloServlet</url-pattern>,則在游覽器地址欄中敲入的應該是http://localhost:8080/mytest/HelloServlet
5. 發布第一個bean(這個例子應用了jsp頁面)
1) 先在C:\Program Files\Apache Software Foundation\Tomcat 5.5\webapps\mytest下建立一個htm文檔transPara.htm
內容為:
<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下建立一個jsp文檔acceptPara.jsp
內容為:
<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
內容為:
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,我們可以看見有姓名、年齡、性別幾個表單,輸入各個項后點擊submit就可以看到我們剛才輸入的結果,大概返回結果如下:
Value of property "name" : Joson
Value of property "age" : 23
Value of property "sex" : male
Value of property "submit" : submit



落花飛雪 2005-09-25 15:17 發表評論
]]>
主站蜘蛛池模板: 国产精品免费大片一区二区| 免费一区二区无码东京热| 免费在线观看一级毛片| 国产线视频精品免费观看视频| 亚洲Av综合色区无码专区桃色 | 亚洲AV无码一区二区三区久久精品| 日日夜夜精品免费视频| 亚洲偷自拍拍综合网| 日本免费一区二区在线观看| 日韩欧美亚洲中文乱码| 亚洲伦理一区二区| 国产在线观看免费视频播放器| a视频免费在线观看| 亚洲日韩精品国产一区二区三区| 国产亚洲AV夜间福利香蕉149| 97人妻无码一区二区精品免费| 一区二区免费在线观看| 亚洲一级片在线观看| 久久影视综合亚洲| 免费毛片在线看片免费丝瓜视频| 国产一级a毛一级a看免费人娇| 国产成人精品日本亚洲网址| 亚洲自偷自偷在线制服| 韩国18福利视频免费观看| 香蕉成人免费看片视频app下载| 成人精品国产亚洲欧洲| 亚洲字幕在线观看| 亚洲免费观看视频| 国产一级淫片免费播放电影| 久久久久免费看成人影片| 亚洲激情校园春色| 亚洲日韩一页精品发布| 午夜dj免费在线观看| 久久久久免费看成人影片| www成人免费视频| 亚洲中文字幕久久精品蜜桃 | 成人免费区一区二区三区| xxxxx做受大片视频免费| 四虎影视久久久免费观看| 九九全国免费视频| 一级一级毛片免费播放|