@(EffecitiveJava)[類設(shè)計(jì)|JAVA基礎(chǔ)]
應(yīng)用場景:
當(dāng)我們準(zhǔn)備實(shí)現(xiàn)一個(gè)具有特殊約束條件類的時(shí)候,假設(shè)類的客戶端會(huì)盡其所能的破壞這個(gè)類的約束條件丁存,因此我們必須保護(hù)性設(shè)計(jì)程序扮叨。
擴(kuò)展:
JAVA是一門安全的語言。這就意味著,它對(duì)緩沖區(qū)溢出锉试、數(shù)組越界瘸洛、非法指針以及其它的內(nèi)存破壞錯(cuò)誤都自動(dòng)免疫揍移,而這些錯(cuò)誤卻困擾著諸如C和C++這樣的不安全的語言。在一門安全的語言中反肋,可以確切的知道那伐,無論系統(tǒng)的其他部分發(fā)生什么事,這些類的約束都可以保持為真石蔗。對(duì)于那些“把內(nèi)存當(dāng)做一個(gè)巨大數(shù)組看待”的語言來說罕邀,這是不可能的。
規(guī)范已經(jīng)注意事項(xiàng)
- 對(duì)于構(gòu)造器的每個(gè)可變參數(shù)進(jìn)行保護(hù)性拷貝
如上圖所示养距,檢查參數(shù)的合法性(約束)是在保護(hù)性拷貝之后進(jìn)行的燃少。而且參數(shù)的合法性的檢查是針對(duì)保護(hù)性拷貝之后的對(duì)象,而不是針對(duì)原始對(duì)象铃在。
這樣做是為了避免危險(xiǎn)階段來自另外一個(gè)線程的修改參數(shù)阵具。危險(xiǎn)階段指的是檢查參數(shù)開始,直至保護(hù)性拷貝參數(shù)之間的時(shí)間定铜。在計(jì)算機(jī)安全社區(qū)中阳液,這段時(shí)間被稱為TOC、TOU(Time-Of-Use,Time-Of-Check)揣炕。
- 對(duì)于參數(shù)類型可以被不可信任類子類化的參數(shù)帘皿,請(qǐng)不要使用clone方法進(jìn)行保護(hù)性拷貝,文摘如下:
原因:不能保證clone方法返回類一定是X類的對(duì)象畸陡,由于JAVA的向上轉(zhuǎn)型特性鹰溜,返回的可能是出于惡意的目的而設(shè)計(jì)的不可信子類的實(shí)例虽填。
- 當(dāng)X類提供了可變內(nèi)部成員的訪問能力時(shí),該訪問返回的應(yīng)該是可變內(nèi)部域的保護(hù)性拷貝曹动。
總結(jié):
保護(hù)性拷貝斋日,不僅僅適用于不可變類。當(dāng)編寫構(gòu)造器或方法時(shí)墓陈,如果它要允許客戶提供的對(duì)象進(jìn)入到內(nèi)部數(shù)據(jù)中恶守,則有必要考慮一下,客戶端提供的對(duì)象是否可能是有變的贡必。如果是兔港,就要考慮到你的類是否能容忍對(duì)象進(jìn)入數(shù)據(jù)結(jié)構(gòu)之后發(fā)生變化。如果答案是否定的仔拟,那么就必須使用保護(hù)性拷貝衫樊,并且讓保護(hù)性拷貝之后的對(duì)象而不是原始對(duì)象進(jìn)入到類的內(nèi)部。
保護(hù)性拷貝可能會(huì)帶來性能損失利花,我覺得這是對(duì)的科侈。類的拷貝明顯會(huì)增加一個(gè)方法執(zhí)行的時(shí)間成本。原文說晋被,這種說法并不總是對(duì)的兑徘,但并沒有指出這種情況,我想了想羡洛,也沒想到挂脑。
保護(hù)性拷貝是可以被代替的。如果某些情況下欲侮,拷貝成本收到限制崭闲,并且類信任它的客戶端不會(huì)不恰當(dāng)?shù)男薷慕M件,可以在文檔中顯示聲明不得修改收到影響的組件威蕉,以此代替保護(hù)性拷貝刁俭。