摘要:檢查參數(shù)的有效性每當(dāng)編寫方法或者構(gòu)造器時,應(yīng)該考慮它的參數(shù)有哪些限制。為了保護實例的內(nèi)部信息避免受到這種攻擊,對于構(gòu)造器的每個可變參數(shù)進行保護性拷貝是必要的,并且使用備份對象作為實例的組件,而不是使用原始的對象。
檢查參數(shù)的有效性
每當(dāng)編寫方法或者構(gòu)造器時,應(yīng)該考慮它的參數(shù)有哪些限制。應(yīng)該把這些限制寫到文檔中,并且在這個方法體開頭處,通過顯示的檢查來實施這些限制。養(yǎng)成這樣的習(xí)慣非常重要。
必要時進行保護性拷貝public final class Period { private final Date start; private final Date end; public Period(Date start, Date end) { if (start.compareTo(end) > 0) { throw new IllegalArgumentException(start + " after " + end); } this.start = start; this.end = end; } public Date start() { return start; } public Date end() { return end; } }
因為Date類本身時可變的,所以,
Date start = new Date(); Date end = new Date(); Period p = new Period(start, end); end.setYear(78); // 這個操作把實例的內(nèi)部信息修改了。
為了保護Period實例的內(nèi)部信息避免受到這種攻擊,對于構(gòu)造器的每個可變參數(shù)進行保護性拷貝是必要的,并且使用備份對象作為Period實例的組件,而不是使用原始的對象。
public Period(Date start, Date end) { this.start = new Date(start.getTime()); this.end = new Date(end.getTime()); if (this.start.compareTo(this.end) > 0) { throw new IllegalArgumentException(start + " after " + end); } }
注意,保護性拷貝是在檢查參數(shù)的有效性之前進行的,并且有效性檢查是針對拷貝之后的對象,而不是原始的對象。
但是改變Period實例仍然是有可能的,因為它的訪問方法提供了對其內(nèi)部成員的訪問能力。
Date start = new Date(); Date end = new Date(); Period p = new Period(start, end); p.end().setYear(78); // 這個操作把實例的內(nèi)部信息修改了。
為了防御這第二種攻擊,只需改這兩個訪問方法,使它返回可變內(nèi)部域的保護性拷貝即可。
public Date start() { return new Date(start.getTime()); } public Date end() { return new Date(end.getTime()); }
在內(nèi)部組件被返回給客戶端之前,對它們進行保護性拷貝也是同樣的道理。
只要有可能,都應(yīng)該使用不可變的對象作為對象內(nèi)部的組件,這樣就不必再為保護性拷貝操心。
如果類具有從客戶端得到或者返回到客戶端的可變組件,類就必須保護性地拷貝這些組件。
如果拷貝的成本受到限制,并且類信任它的客戶端會恰當(dāng)?shù)匦薷慕M件,就可以在文檔中指明客戶端的職責(zé)使不得修改受到影響的組件,以此來代替保護性拷貝。
首要目標(biāo)是選擇易于理解的。
第二目標(biāo)是選擇與大眾認可的名稱相一致的名稱。
不要過于追求提供便利的方法每個方法都應(yīng)該盡其所能。方法太多會使類難以學(xué)習(xí)、使用、文檔化、測試和維護。
對于類和接口所支持的每個動作,都提供一個功能齊全的方法。
避免過長的參數(shù)列表目標(biāo)是四個參數(shù),或者更少。
有三種方法可以縮短過長的參數(shù)列表。
第一種是把方法分解成多個方法,每個方法只需要這些參數(shù)的一個子集。
第二種是創(chuàng)建輔助類,用來保存參數(shù)的分組。
第三種是從對象構(gòu)建到方法調(diào)用都采用Builder模式。
如果使用的是類而不是接口,則限制了客戶端只能傳入特定的實現(xiàn),如果碰巧輸入的數(shù)據(jù)是以其他的形式存在,就會導(dǎo)致不必要的、可能非常昂貴的拷貝操作。
對于boolean參數(shù),要優(yōu)先使用兩個元素的枚舉類型它是代碼更易于閱讀和編寫,也使以后更易于添加更多的選項。
慎用重載下面的程序試圖根據(jù)一個集合是Set、List,還是其他的集合類型來分類。
public class CollectionClassifier { public static String classify(Set> set) { return "Set"; } public static String classify(List> list) { return "List"; } public static String classify(Collection> collection) { return "Unknow Collection"; } public static void main(String[] args) { Collection>[] collections = { new HashSet(), new ArrayList (), new HashMap ().values() }; for(Collection> collection : collections) { System.out.println(classify(collection)); } } }
可能期望會打印“Set”,接著是“List”,以及“Unknow Collection”,實際上不是這樣。而是“Unknow Collection”打印三次。
因為classify方法被重載(overload)了,而要調(diào)用哪個重載方法是在編譯時做出決定的。對于for循環(huán)中的三次迭代,參數(shù)的編譯時類型都是相同的,Collection>。每次迭代的運行時類型都是不同的,但這并不影響對重載方法的選擇。因為該參數(shù)的編譯時類型為Collection>,所以,唯一合適的重載方法是第三個,classify(Collection>),在循環(huán)的每次迭代中,都會調(diào)用這個重載方法。
對于重載方法(overload method)的選擇是靜態(tài)的,而對于被覆蓋的方法(overriden method)的選擇則是動態(tài)的。
選擇被覆蓋的方法的正確版本是在運行時的,選擇的依據(jù)時被調(diào)用方法所在對象的運行時類型。
再看看下面這個程序。
class Wine { String name() { return "wine"; } } class SparklingWine extends Wine { @Override String name() { return "sparkling wine"; } } class Champagne extends SparklingWine { @Override String name() { return "champagne"; } } public class Overriding { public static void main(String[] args) { Wine[] wines = { new Wine(), new SparklingWine(), new Champagne() }; for(Wine wine : wines) { System.out.println(wine.name()); } } }
這個程序打印“wine”、“sparkling wine”和“champagne”。
可以對第一個程序修改一下,用單個方法替換三個重載的classify方法,如下。
public static String classify(Collection> collection) { return collection instanceof Set ? "Set" : collection instanceof List ? "List" : "Unknow Collection"; }
因為覆蓋機制時規(guī)范,而重載機制是例外。
到底怎樣才算是胡亂使用重載機制呢?這個問題仍有爭議。安全而保守的策略是,永遠不要導(dǎo)出兩個具有相同參數(shù)數(shù)目的重載方法。
慎用可變參數(shù)Java 1.5發(fā)行版本中增加了可變參數(shù)方法,一般稱作variable arity method(可匹配不同長度的變量方法)[JLS,8.4.1]。
可變參數(shù)方法接受零個或者多個指定類型的參數(shù)。可變參數(shù)機制通過先創(chuàng)建一個數(shù)組,數(shù)組的大小為在調(diào)用位置所傳遞的參數(shù)數(shù)量,然后將參數(shù)值傳到數(shù)組中,最后將數(shù)組傳遞給方法。
static int sum(int... args) { int sum = 0; for (int arg : args) { sum += arg; } return sum; }
當(dāng)真正需要讓一個方法帶有不定數(shù)量的參數(shù)時,可變參數(shù)就非常有效。可變參數(shù)是為printf而設(shè)計的。printf和反射機制都從可變參數(shù)中極大地受益。
在重視性能地情況下,需要小心。可變參數(shù)方法的每次調(diào)用都會導(dǎo)致進行一次數(shù)組分配和初始化。
需要可變參數(shù)的靈活性,但又無法承受性能成本,可以這么做。
public void foo() {} public void foo(int a1) {} public void foo(int a1, int a2) {} public void foo(int a1, int a2, int a3) {} public void foo(int a1, int a2, int a3, int... rest) {}
在定義參數(shù)數(shù)目不定的方法時,可變參數(shù)方法是一種很方便的方式,但是不應(yīng)該被過度濫用。如果使用不當(dāng),會產(chǎn)生混亂的結(jié)果。
返回零長度的數(shù)組或者集合,而不是null對于一個返回null而不是零長度數(shù)組或者集合的方法,幾乎每次調(diào)用該方法都需要曲折的處理方式。這樣很容易出錯,因為編寫客戶端程序的程序員可能會忘記寫專門的代碼來處理null返回值。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/70055.html
摘要:只針對異常的情況才使用異常下面展示兩種遍歷數(shù)組元素的實現(xiàn)方式。第一種方式在訪問數(shù)組邊界之外的第一個數(shù)組元素時,用拋出捕獲忽略異常的手段來達到終止無限循環(huán)的目的。這種做法被稱為異常轉(zhuǎn)譯。 只針對異常的情況才使用異常 下面展示兩種遍歷數(shù)組元素的實現(xiàn)方式。 try { int i = 0; while(true) range[i++].climb(); } c...
摘要:學(xué)習(xí)編程的本最佳書籍這些書涵蓋了各個領(lǐng)域,包括核心基礎(chǔ)知識,集合框架,多線程和并發(fā),內(nèi)部和性能調(diào)優(yōu),設(shè)計模式等。擅長解釋錯誤及錯誤的原因以及如何解決簡而言之,這是學(xué)習(xí)中并發(fā)和多線程的最佳書籍之一。 showImg(https://segmentfault.com/img/remote/1460000018913016); 來源 | 愿碼(ChainDesk.CN)內(nèi)容編輯 愿碼Slo...
摘要:來源前條來源一書英文版已經(jīng)出版,這本書的第二版想必很多人都讀過,號稱四大名著之一,不過第二版年出版,到現(xiàn)在已經(jīng)將近年的時間,但隨著,,,甚至的發(fā)布,語言發(fā)生了深刻的變化。譯者在這里第一時間翻譯成中文版。供大家學(xué)習(xí)分享之用。 來源:sjsdfg/effective-java-3rd-chinese前 51 條來源:Effective Java, Third Edition 《Effec...
摘要:這本書是我第一次買的,從買來至今整本書還沒有看完,只看了一半,原因是個人比較懶,而且玩的心比較大,經(jīng)過這么多年的沉淀,終于可以偷點時間寫下對于這本書的觀后感了整本書給我的感覺不像是一個技術(shù)書,更多的是講解一些實用技巧,而對于我這個職場菜鳥來 effective Java 這本書是我第一次買的, 從買來至今整本書還沒有看完, 只看了一半, 原因是個人比較懶,而且玩的心比較大,經(jīng)過這么多年...
摘要:三進階階段這個階段主要是靠我們自己學(xué)習(xí)總結(jié),可以通過前輩們的博客或者自己研究源碼,這些非常有利于我們快速的成長。讓自己保持永遠學(xué)習(xí)的精神。五零基礎(chǔ)學(xué)習(xí)資料最后給大家準(zhǔn)備了一份不錯的學(xué)習(xí)資源,里面有很多學(xué)習(xí)視頻和資料,后臺回復(fù)資源,即可獲取。 showImg(https://segmentfault.com/img/bVbauV8?w=1212&h=816); 前兩次給大家分享了關(guān)于 j...
閱讀 2135·2019-08-29 16:53
閱讀 2712·2019-08-29 16:07
閱讀 2054·2019-08-29 13:13
閱讀 3277·2019-08-26 13:57
閱讀 1342·2019-08-26 13:31
閱讀 2446·2019-08-26 13:22
閱讀 1232·2019-08-26 11:43
閱讀 2095·2019-08-23 17:14