摘要:如果采用抽象類,則屬性組合可能導(dǎo)致子類的組合爆炸。內(nèi)部類的設(shè)計靜態(tài)成員類用修飾的內(nèi)部類,可以不依賴于外部實例進行創(chuàng)建。如下所示其構(gòu)造函數(shù)默認是,并且無法修改。
對所有對象都通用的方法 equals和hashCode方法的關(guān)系
重寫equals方法必須也要重寫hashCode方法。
equals用的屬性沒變,則多次調(diào)用hashCode返回值也必須保持不變。
equals比較相等的對象,hashCode也必須相同。反之不然。
所處相同hash bucket的對象,hashCode可能不同,因為在求解bucket位置時會對hashCode進行截斷,根據(jù)bucket大小采用后段值。
clone方法的設(shè)計原則Cloneable接口并不提供接口方法clone,clone是Object類實現(xiàn)的基本方法。
實現(xiàn)Cloneable接口的類應(yīng)該提供一個public的clone函數(shù)覆蓋原來protect的方法。
clone方法首先調(diào)用super的clone方法,然后再處理需要深層拷貝的內(nèi)部屬性。
道行不深不要使用該接口。
Comparable接口的設(shè)計原則不可變對象線程安全,可以被自由的共享。不可變類不應(yīng)該提供clone和拷貝構(gòu)造器,直接共享最好,但是String還是提供了拷貝構(gòu)造器。
不可變類也有一定的劣勢,因為一個操作可能涉及多個臨時的不可變類,而導(dǎo)致大量對象的創(chuàng)建和銷毀,所以此時應(yīng)該采用不可變類配套的可變類。如String類對應(yīng)的StringBuilder。
應(yīng)該提供盡可能小的可變狀態(tài)。
復(fù)合優(yōu)先于繼承繼承會破壞封裝性,實現(xiàn)繼承需要對父類的實現(xiàn)進行充分的了解。所以父類和子類應(yīng)該實現(xiàn)在同一個包內(nèi),由同一個開發(fā)團隊維護。
一個類在設(shè)計時應(yīng)該明確指明是不是為了可被繼承而設(shè)計的。
一個類如果沒有考慮自己可能被繼承,有些方法可能會被重寫,則其內(nèi)部調(diào)用這些可被重寫方法的方法就可能會出現(xiàn)意想不到的異常行為。繼承該方法的子類會調(diào)用父類的內(nèi)部方法,而父類內(nèi)部方法的更新可能會導(dǎo)致子類的異常。
接口優(yōu)于抽象類現(xiàn)有的類可以很容易的加入新的接口,因為接口可以實現(xiàn)多個。
類只允許有一個父類,如果用抽象類描述共性,則需要該共性的類必須為該抽象類的后代,即使這些子類并沒有很顯然的關(guān)系。
接口可以讓我們實現(xiàn)非層次結(jié)構(gòu)的類框架。如果采用抽象類,則屬性組合可能導(dǎo)致子類的組合爆炸。
接口的缺點是擴展新方法時,所有實現(xiàn)該接口的類都要重新添加該方法,而抽象類可以提供默認實現(xiàn)。不過,現(xiàn)在Java8提供了default描述默認實現(xiàn)方法,似乎這種弊端可以避免。
接口中定義屬性接口中定義的屬性默認為final static。
最好不要用接口來定義屬性,因為實現(xiàn)該接口的類會引入這些屬性,造成類的命名空間污染。接口應(yīng)該用來描述類可以執(zhí)行的動作。
內(nèi)部類的設(shè)計靜態(tài)成員類:用static修飾的內(nèi)部類,可以不依賴于外部實例進行創(chuàng)建。
非靜態(tài)成員類:創(chuàng)建時依賴于外部類的實例,并且創(chuàng)建后與外部實例綁定。無靜態(tài)屬性。
匿名內(nèi)部類:作為參數(shù),只會被實例化一次。和非靜態(tài)成員類似。在非靜態(tài)環(huán)境中,會與外部類的實例綁定。
局部類:聲明局部變量的地方可以聲明局部類,它有名字,可以在局部被多次實例化。在非靜態(tài)環(huán)境中,會與外部類的實例綁定。
泛型 不要在代碼中使用原生類型如下代碼使用原生類型:
ArrayList a=new ArrayList(); a.add(new Object());
以上代碼編譯和運行都可以通過,但是埋下了很多隱患。
List
List中add任何對象都對。List>的變量可以引用任何參數(shù)化(非參數(shù)也可以)的List,但是無法通過該變量添加非null元素。
假設(shè)Men extends Person, Boy extends Men:
extends T>表示上界,<? super T>表示下界。
ArrayList extends Men> ml=new ArrayList
ArrayList super Men> ml=new ArrayList
總結(jié)2和3條,可知 extends T>和<? super T>是對等號右邊實參數(shù)化ArrayList的限制,而不是對ArrayList中可存入元素的描述。因為從引用ml中無法得知其實際指向的是那種參數(shù)化的ArrayList實例,所以再往其中添加元素時會采用最謹慎的選擇。
列表和數(shù)組的區(qū)別數(shù)組是協(xié)變的,也就是Fruit[] fs= new Apple[5];是合法的,因為Apple是Fruit的子類,則數(shù)組也成父子關(guān)系,而列表則不適用于該規(guī)則。數(shù)組的這種關(guān)系容易引發(fā)錯誤,如fs[0]= new Banana(),編譯時沒錯,這在運行時報錯。
創(chuàng)建泛型數(shù)組是非法的,如new E[]; new List
如下代碼在編譯時不會出錯,在運行時出錯java.lang.ClassCastException。
ArrayListlist=new ArrayList (); for (int i = 0; i < 10; i++) { list.add(""+i); } //該行報錯 String[] array= (String[]) list.toArray(); }
原因很迷,toArray返回的是Object[]數(shù)組,但是不能強制轉(zhuǎn)化為String[],明明元素實際類型是String。有的解釋說,在運行時只有List的概念,而沒有List
泛型是在整個類上采用泛型,這樣可以在類內(nèi)部方便的使用泛型參數(shù)。泛型方法是更精細的利用參數(shù)類型,將泛型參數(shù)設(shè)定在每個方法上。
比較下面兩個接口,體會其中不同:
public interface Comparable遞歸類型限制{ public int compareTo(T o); } public interface Comparable2 { public int compareTo2(T o); } public class Apple implements Comparable , Comparable2{ @Override public int compareTo(Apple o) { return 0; } @Override public int compareTo2(T o) { //T 可以為任何類,所以Apple可以和任何類比較 return 0; } }
有類:
class Apple implements Comparable{ } class RedApple extends Apple{ }
有方法:
public static> T get(T t){ return t; }
該方法就采用了遞歸的類型限制,因為泛型T被限制為 Comparable
RedApple ra=new RedApple(); Apple a= get(ra); //正確 RedApple b=get(ra); //錯誤
原因是在調(diào)用泛型函數(shù)時,會自動進行類型推斷,第一個get函數(shù)根據(jù)左邊參數(shù),推斷T為Apple,符合條件。在第二個get公式中,推斷T為RedApple,不符合get函數(shù)的泛型限制條件。
一個比較復(fù)雜的泛型函數(shù)public static> T max(List extends T> list)
其中
一個容器如Set只有1個類型參數(shù),Map只有2個類型參數(shù),但是有時候需要多個類型參數(shù)。下面是一個設(shè)計巧妙、可以容納多個類型參數(shù)的類。
public static void main(String[] args){ Favorites f =new Favorites(); f.putFavorite(String.class, "Java"); f.putFavorite(Integer.class, 1111); f.putFavorite(Class.class, Favorites.class); int fi=f.getFavorite(Integer.class); } public class Favorites{ private Map, Object> favorites=new HashMap , Object>(); public void putFavorite(Class type, T instance){ if(type==null) throw new NullPointerException("Type is null"); favorites.put(type, instance); } public T getFavorite(Class type){ return type.cast(favorites.get(type)); } }
String.class為Class
其中Map實例favorites并沒有限制value一定是key描述的類的實例,而方法putFavorite通過類型參數(shù)T,巧妙的限制了兩者的關(guān)系。
枚舉和注解 枚舉類型舉例枚舉類型更像是一個不能new的類,只能在定義時就實例化好需要的固定數(shù)目的實例。如下所示:
public enum Planet { VENUS(2), EARTH(3), MARS(5); int data; Planet(int i){ this.data=i; } public int getData(){ return data; } }
其構(gòu)造函數(shù)默認是private,并且無法修改。在枚舉中還可以定義抽象方法,如下:
public enum Operation{ PLUS { double apply(double x, double y){return x+y;}}, MINUS { double apply(double x, double y){return x-y}}; abstract double apply(double x, double y); }自定義注解的例子
定義一個用來測試方法是否能拋出目標異常的注解。
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ExceptionTest{ Class extends Exception>[] value(); }
元注解指明了該注解在運行時保留,并且只適用于注解方法。
使用如下:
@ExpectionTest({IndexOutOfBoundsException.class, NullPointerException.class}) public static void doublyBad(){ Listlist=new ArrayList (); //該方法會拋出IndexOutOfBoundsException list.addAll(5,null); }
測試過程實現(xiàn)如下:
public static void main(String[] args) throws Exception{ int tests=0; int passed=0; Class testClass=Class.forName(args[0]); for(Method m : testClass.getDeclaredMethods()){ if(m.isAnnotationPresent(ExceptionTest.class)){ tests++; try{ m.invoke(null); System.out.printf("Test failed: no exceptions"); }catch( Throwable wrappedExc){ Throwable exc = wrappedExc.getCause(); Class extends Exception>[] excTypes=m.getAnnotation(ExceptionText.class).value(); int oldPaassed=passed; for(Class extends Exception> excType:excTypes){ if(excType.isInstance(exc)){ passed++; break; } } if(passed==oldPassed) System.out.printf("Test failed"); } } } }方法 必要時進行保護性拷貝
構(gòu)造函數(shù)在接受外來參數(shù)時,必要時需要拷貝參數(shù)對象,而不是直接將參數(shù)對象賦值給自己的屬性。因為直接采用外部傳入的對象,外部可以任意的修改這些對象,從而導(dǎo)致你自己設(shè)計的類內(nèi)部屬性變化。如果不想讓使用你設(shè)計的類的客戶有修改其內(nèi)部屬性的權(quán)利,除了設(shè)置為private外,還應(yīng)該注意采用拷貝的方式使用外部傳入的數(shù)據(jù)。選擇copy而不是clone,是因為傳入對象可能是客戶定制過的參數(shù)子類,該子類仍然可能將其暴露在外面。
需要保護內(nèi)部屬性不被修改,除了關(guān)注構(gòu)造函數(shù)的參數(shù),還需要關(guān)注get類似的方法。這些返回內(nèi)部屬性的方法,應(yīng)該返回拷貝過的屬性對象。
慎用重載重載方法是靜態(tài)的,在編譯時就已經(jīng)選擇好,根據(jù)參數(shù)的表面類型,如Collection
而方法的重寫選擇時動態(tài)的,在運行時根據(jù)調(diào)用者的實際類型決定哪個方法被調(diào)用。
慎用可變參數(shù)可變參數(shù)可以讓用戶靈活的填入不同數(shù)量的參數(shù),但是該方法本質(zhì)上是將參數(shù)組織成數(shù)組,所以每次調(diào)用這些方法時都會涉及數(shù)組的創(chuàng)建和銷毀,開銷較大。
并發(fā) 同步的意義保證數(shù)據(jù)從一個一致狀態(tài)轉(zhuǎn)一到另一個一致狀態(tài),任何時候讀取該數(shù)據(jù)都是一致的。
保證對數(shù)據(jù)的修改,其它線程立即可見。
讀寫變量是原子性的除了double和long以外,讀寫變量是原子性的。但是Java無法保證一個線程的修改對另一個線程是可見的。
在同步模塊中小心調(diào)用其它方法如果一個同步方法在其中調(diào)用了一個不由自己控制的方法,比如客戶傳入的方法,客戶可能在實現(xiàn)方法時申請同步鎖,或者啟動新線程申請鎖,這可能會導(dǎo)致死鎖。
并發(fā)工具優(yōu)先于wait和notifyjava.util.concurrent包提供了執(zhí)行框架、并發(fā)集合和同步器三種工具,應(yīng)該盡量使用這些工具來實現(xiàn)并發(fā)功能,而不是使用wait、notify。
如果使用wait,notify則應(yīng)該采用如下模式:
public void waitA(){ synchronized(a){ //獲得鎖 while(a>10) //放在while循環(huán)中保證滿足條件 try { a.wait(); //釋放鎖、如果被喚醒則需要重新獲得鎖 } catch (InterruptedException e) { e.printStackTrace(); } } } //其它線程調(diào)用該方法喚醒等待線程 public void notifyA(){ a.notifyAll(); }
notifyAll方法相較于notify方法更安全,它保證喚醒了所有等待a對象的線程,被喚醒不代表會被立即執(zhí)行,因為還需要獲得鎖。
不要對線程調(diào)度器有任何期望Tread yield(讓步)即當前線程將資源歸還給調(diào)度器,但是并不能保證當前線程下面一定不會被選中。線程的優(yōu)先級設(shè)置也是不能保證按你預(yù)期的進行調(diào)度。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/69409.html
摘要:構(gòu)造器的參數(shù)沒有確切地描述其返回的對象,適當名稱的靜態(tài)工廠方法更容易使用,也易于閱讀。在文檔中,沒有像構(gòu)造器那樣明確標識出來,因此,對于提供了靜態(tài)工廠方法而不是構(gòu)造器的類來說,要查明如何實例化一個類,有點困難。 第二章 創(chuàng)建和銷毀對象 第1條 考慮用靜態(tài)工廠方法代替構(gòu)造器 兩者創(chuàng)建對象的形式,例如:構(gòu)造器是new Boolean();靜態(tài)工廠方法是 public static Bool...
摘要:這本書是我第一次買的,從買來至今整本書還沒有看完,只看了一半,原因是個人比較懶,而且玩的心比較大,經(jīng)過這么多年的沉淀,終于可以偷點時間寫下對于這本書的觀后感了整本書給我的感覺不像是一個技術(shù)書,更多的是講解一些實用技巧,而對于我這個職場菜鳥來 effective Java 這本書是我第一次買的, 從買來至今整本書還沒有看完, 只看了一半, 原因是個人比較懶,而且玩的心比較大,經(jīng)過這么多年...
摘要:第二章創(chuàng)建和銷毀對象何時以及如何創(chuàng)建對象,何時以及如何避免創(chuàng)建對象,如何確保他們能夠適時地銷毀,以及如何管理對象銷毀之前必須進行的各種清理動作。表示工廠方法所返回的對象類型。 第二章 創(chuàng)建和銷毀對象 何時以及如何創(chuàng)建對象,何時以及如何避免創(chuàng)建對象,如何確保他們能夠適時地銷毀,以及如何管理對象銷毀之前必須進行的各種清理動作。 1 考慮用靜態(tài)工廠方法代替構(gòu)造器 一般在某處獲取一個類的實例最...
閱讀 1448·2019-08-29 17:14
閱讀 1650·2019-08-29 12:12
閱讀 730·2019-08-29 11:33
閱讀 3266·2019-08-28 18:27
閱讀 1444·2019-08-26 10:19
閱讀 909·2019-08-23 18:18
閱讀 3529·2019-08-23 16:15
閱讀 2543·2019-08-23 14:14