環(huán)境:win32,Eclipse3.1,Designer_v
1. 首先去http://www.swt-designer.com/左邊的download菜單點(diǎn)擊進(jìn)去后下載Edition for Eclipse 3.1 & 3.2,下載后的文件名為Designer_v
2. 然后在我的網(wǎng)絡(luò)硬盤(pán)中下載破解文件: 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)和激活碼。
如果你所使用的環(huán)境和版本不是win32,Eclipse3.1,Designer_v
a) 將該目錄下的org.eclipse.swt.win32.win32.x86_
b)在Eclipse目錄下找到swt.jar(名字視版本而定,eclipse3.1下是org.eclipse.swt.win32.win32.x86_
c)修改swt.ui.bat,如這樣:
原來(lái)是: start javaw -cp SWTDesigner_
修改為:start javaw -cp SWTDesigner_
紅色為修改的地方,然后運(yùn)行后將Version填入你下載的swt-designer版本號(hào)即可產(chǎn)生注冊(cè)碼。
4. 將下載的Designer_v
運(yùn)行eclipse,打開(kāi)window->preferences…->選擇左邊樹(shù)形中的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了
Win32下MyEclipse4.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)支持正版。(形式?)
下邊的條列只是簡(jiǎn)單的介紹,以便忘記了偶爾過(guò)來(lái)游覽一下,詳細(xì)的介紹請(qǐng)參閱:《Java模式》、《UML和模式應(yīng)用-面向?qū)ο蠓治雠c設(shè)計(jì)導(dǎo)論》
1. GRASP模式
GRASP是General Responsibility Assignment Software Pattern(通用指責(zé)分配軟件模式)的縮寫(xiě)。
1) 專家模式(Expert)
解決方案:將職責(zé)分配給具有履行職責(zé)所需要的信息的類
通俗點(diǎn)就是:該干嘛干嘛去,別管別人的閑事或者我的職責(zé)就是搞這個(gè),別的事不管。
舉個(gè)簡(jiǎn)單的例子,如果有一個(gè)類是專門(mén)處理字符串相關(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) B是A對(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è)專門(mén)的接口比使用單一的總接口要好。也就是,從一個(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)任何功能。
許多人都做過(guò)這樣的事情,但是,我們到底聲明了什么?回答通常是:一個(gè)String,內(nèi)容是“Hello world!”。這樣模糊的回答通常是概念不清的根源。如果要準(zhǔn)確的回答,一半的人大概會(huì)回答錯(cuò)誤。
這個(gè)語(yǔ)句聲明的是一個(gè)指向?qū)ο蟮囊茫麨椤皊”,可以指向類型為String的任何對(duì)象,目前指
1. 聲明是什么?
String s = "Hello world!";
許多人都做過(guò)這樣的事情,但是,我們到底聲明了什么?回答通常是:一個(gè)String,內(nèi)容是“Hello world!”。這樣模糊的回答通常是概念不清的根源。如果要準(zhǔn)確的回答,一半的人大概會(huì)回答錯(cuò)誤。
這個(gè)語(yǔ)句聲明的是一個(gè)指向?qū)ο蟮囊茫麨椤皊”,可以指向類型為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文, 寫(xiě)共函。 另: 編繹器對(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ò)編譯。總之,要保證局部變量在使用之前一定被初始化了。所以,一個(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ū)別
==操作符專門(mén)用來(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的值為T(mén)rue。
instanceof有一些用處。比如我們寫(xiě)了一個(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)工廠方法。
目前我就用了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"
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
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ò)輸出流向客戶端寫(xiě)回了一個(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>
年 齡: <input type="text" name="age" size="15"><br>
性 別:
<input type="radio" value="male" checked name="sex">
男
<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