亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

Effective Java讀書筆記三:創建和銷毀對象(1-7)

2019-11-14 10:16:25
字體:
來源:轉載
供稿:網友

第1條:考慮用靜態工廠方法代替構造器

對于類而言,為了讓客服端獲得它的一個實例最常用的的一個方法就是提供一個公有的構造器。還有一種方法,類可以提供一個公有的靜態工廠方法(static factory method),它只是一個返回類實例的靜態方法。

通過靜態工廠方法構造對象的優勢:

靜態工廠方法與構造器不同的第一大優勢在于,它們有名稱,使客服端代碼更加容易被閱讀。 不必在每次調用的它們的時候都創建一個新的對象(這個完全取決于具體的實現)。 它們可以返回原返回類型的任何子類型的對象。 這種靈活性的一種應用:API可以返回對象,同時又不會使對象的類變成公有的。公有的靜態方法所返回的對象的類不僅可以是非公有的,而且該類還可以隨著每次調用而發生變化著取決于靜態工廠方法的參數值,只要是已聲明返回類型的子類型,都是允許的。在創建參數化類型(也就是泛型,jdk1.5新特性)實例的時候,它們是的代碼變得更加簡潔。/**普通創建****/ Map<String,List<String>> m=new HashMap<String,List<String>>; /**有了靜態方法過后***/ Map<String,List<String>> m=HashMap.newInstance(); //前提HashMap提供了這個靜態工廠方法 public static <k,v> HashMap<k,v> newInstance(){ return new HashMap<K,V>(); }

靜態工廠方法的主要缺點在于:

類如果不含有他的公有或者受保護的構造器,就不能被子類化(即被繼承)。它們與其他靜態方法實際上沒有任何區別。

常用的靜態工廠名稱:valueOf,of,getInstance,newInstance,getType,newType.

第2條:遇到多個構造參數時要考慮用構建器(Builder模式)

class NutritionFacts { PRivate final int servingSize; private final int servings; private final int calories; private final int fat; private final int sodium; private final int carbohydrate; public static class Builder { //對象的必選參數 private final int servingSize; private final int servings; //對象的可選參數的缺省值初始化 private int calories = 0; private int fat = 0; private int carbohydrate = 0; private int sodium = 0; //只用少數的必選參數作為構造器的函數參數 public Builder(int servingSize,int servings) { this.servingSize = servingSize; this.servings = servings; } public Builder calories(int val) { calories = val; return this; } public Builder fat(int val) { fat = val; return this; } public Builder carbohydrate(int val) { carbohydrate = val; return this; } public Builder sodium(int val) { sodium = val; return this; } public NutritionFacts build() { return new NutritionFacts(this); } } private NutritionFacts(Builder builder) { servingSize = builder.servingSize; servings = builder.servings; calories = builder.calories; fat = builder.fat; sodium = builder.sodium; carbohydrate = builder.carbohydrate; } } //使用方式 public static void main(String[] args) { NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).calories(100) .sodium(35).carbohydrate(27).build(); System.out.println(cocaCola); }

對于Builder方式,可選參數的缺省值問題也將不再困擾著所有的使用者。這種方式還帶來了一個間接的好處是,不可變對象的初始化以及參數合法性的驗證等工作在構造函數中原子性的完成了。

第3條:用私有構造器或者枚舉類型強化Singleton屬性

1、將構造函數私有化,直接通過靜態公有的final域字段獲取單實例對象:

public class Elvis { public static final Elvis INSTANCE = new Elvis(); private Elivs() { ... } public void leaveTheBuilding() { ... } }

這樣的方式主要優勢在于簡潔高效,使用者很快就能判定當前類為單實例類,在調用時直接操作Elivs.INSTANCE即可,由于沒有函數的調用,因此效率也非常高效。然而事物是具有一定的雙面性的,這種設計方式在一個方向上走的過于極端了,因此他的缺點也會是非常明顯的。如果今后Elvis的使用代碼被遷移到多線程的應用環境下了,系統希望能夠做到每個線程使用同一個Elvis實例,不同線程之間則使用不同的對象實例。那么這種創建方式將無法實現該需求,因此需要修改接口以及接口的調用者代碼,這樣就帶來了更高的修改成本。

2、 通過公有域成員的方式返回單實例對象:

public class Elvis { public static final Elvis INSTANCE = new Elvis(); private Elivs() { ... } public static Elvis getInstance() { return INSTANCE; } public void leaveTheBuilding() { ... } }

這種方法很好的彌補了第一種方式的缺陷,如果今后需要適應多線程環境的對象創建邏輯,僅需要修改Elvis的getInstance()方法內部即可,對用調用者而言則是不變的,這樣便極大的縮小了影響的范圍。至于效率問題,現今的JVM針對該種函數都做了很好的內聯優化,因此不會產生因函數頻繁調用而帶來的開銷。

3、使用枚舉的方式(java SE5):

public enum Elvis { INSTANCE; public void leaveTheBuilding() { ... } }

就目前而言,這種方法在功能上和公有域方式相近,但是他更加簡潔更加清晰,擴展性更強也更加安全。

第4條:通過私有構造器強化不可實例化的能力

對于有些工具類如java.lang.Math、java.util.Arrays等,其中只是包含了靜態方法和靜態域字段,因此對這樣的class實例化就顯得沒有任何意義了。然而在實際的使用中,如果不加任何特殊的處理,這樣的classes是可以像其他classes一樣被實例化的。這里介紹了一種方式,既將缺省構造函數設置為private,這樣類的外部將無法實例化該類,與此同時,在這個私有的構造函數的實現中直接拋出異常,從而也避免了類的內部方法調用該構造函數。

public class UtilityClass { //Suppress default constructor for noninstantiability. private UtilityClass() { throw new AssertionError(); } }

這樣定義之后,該類將不會再被外部實例化了,否則會產生編譯錯誤。然而這樣的定義帶來的最直接的負面影響是該類將不能再被子類化。

第5條:避免創建不必要的對象

一般來說,最好能重用對象而不是在每次需要的時候就創建一個相同功能的新對象。如果對象是不可變的,它就始終可以被重用。 反例:

String s = new String(“stringette”);

該語句每次被執行的時候都創建一個新的String實例,但是這些創建對象的動作全都是不必要的,傳遞給String構造器的參數(“stringette”)本身就是一個String實例,功能方面等同于構造器創建的對象。如果這種用法是在一個循環中,或者是在一個被頻繁調用的方法中,就會創建出很多不必要的String實例。 改進:

String s = “stringette”;

改進后,只用一個String實例,而不是每次執行的時候都創建一個新的實例,而且,它可以保證,對于所有在同一虛擬機中運行的代碼,只要它們包含相同的字符串字面常量,該對象就會被重用。

對于同時提供了靜態工廠方法和構造器的不可變類,通常可以使用靜態工廠方法而不是構造器,以避免創建不必要的對象。 例如,靜態工廠方法Boolean.valueOf(String)幾乎總是比構造器Boolean(String)好,構造器在每次被調用的時候都會創建一個新的對象,而靜態工廠方法則從來不要求這樣做,實際上也不會這樣做。

要優先使用基本類型而不是裝箱基本類型,要當心無意識的自動裝箱

public static void main(String[] args) { Long sum = 0L; for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += i; } System.out.println(sum);}

這段程序算出的答案是正確的,但是比實際情況要更慢一些,只因為打錯了一個字符。變量sum被聲明成Long而不是long,這就意味著程序構造了大約2^31個多的Long實例。

Java共有9中基本類型,同別的語言有重要區別的是這9中類型所占存儲空間大小與機器硬件架構無關,這使得Java程序有很強的可移植性,如下圖:

這里寫圖片描述

不要錯誤地認為“創建對象的代價非常昂貴,我們應該要盡可能地避免創建對象,而不是不創建對象”,相反,由于小對象的構造器只做很少量的工作,所以,小對象的創建和回收動作是非常廉價的,特別是在現代的JVM實現上更是如此。通過創建附加的對象,提升程序的清晰性、簡潔性和功能性,這通常也是件好事。

反之,通過維護自己的對象池來創建對象并不是一種好的做法,除非池中的對象是非常重量級的。真正正確使用對象池的典型對象示例就是數據庫連接池。建立數據庫連接的代價是非常昂貴的,因此重用這些對象非常有意義。

另外,在1.5版本里,對基本類型的整形包裝類型使用時,要使用形如 Byte.valueOf來創建包裝類型,因為-128~127的數會緩存起來,所以我們要從緩沖池中取,Short、Integer、Long也是這樣。

第6條:消除過期的對象引用

盡管Java不像C/C++那樣需要手工管理內存資源,而是通過更為方便、更為智能的垃圾回收機制來幫助開發者清理過期的資源。即便如此,內存泄露問題仍然會發生在你的程序中,只是和C/C++相比,Java中內存泄露更加隱匿,更加難以發現,見如下代碼:

public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(Object e) { ensureCapacity(); elements[size++] = e; } public Object pop() { if (size == 0) throw new EmptyStackException(); return elements[--size]; } private void ensureCapacity() { if (elements.length == size) elements = Arrays.copys(elements,2*size+1); } }

這段程序有一個“內存泄漏”問題,如果一個棧先是增長,然后再收縮,那么,從棧中彈出來的對象不會被當做垃圾回收,即使使用棧的程序不再引用這些對象,它們也不會被回收。這是因為,棧內部維護這對這些對象的過期使用(obsolete reference),過期引用指永遠也不會被解除的引用。 修復的方法很簡單:一旦對象引用已經過期,只需要清空這些引用即可。對于上述例子中的Stack類而言,只要一個單元彈出棧,指向它的引用就過期了,就可以將它清空。

修改方式如下:

public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; //手工將數組中的該對象置空 return result; }

Stock為什么會有內存泄漏問題呢? 問題在于,Stock類自己管理內存。存儲池中包含了elements數組(對象引用單元,而不是對象本身)的元素。數組活動區域的元素是已分配的,而數組其余部分的元素是自由的。但是垃圾回收器并不知道這一點,就需要手動清空這些數組元素。 一般而言,只要類是自己管理內存,就應該警惕內存泄漏問題。一旦元素被釋放掉,則該元素中包含的任何對象引用都應該被清空。

由于現有的Java垃圾收集器已經足夠只能和強大,因此沒有必要對所有不在需要的對象執行obj = null的顯示置空操作,這樣反而會給程序代碼的閱讀帶來不必要的麻煩,該條目只是推薦在以下3中情形下需要考慮資源手工處理問題:

類是自己管理內存,如例子中的Stack類。使用對象緩存機制時,需要考慮被從緩存中換出的對象,或是長期不會被訪問到的對象。事件監聽器和相關回調。用戶經常會在需要時顯示的注冊,然而卻經常會忘記在不用的時候注銷這些回調接口實現類。

第7條:避免使用終結方法

Java的語言規范中并沒有保證終結方法會被及時的執行,甚至都沒有保證一定會被執行。即便開發者在code中手工調用了System.gc和System.runFinalization這兩個方法,這僅僅是提高了finalizer被執行的幾率而已。還有一點需要注意的是,被重載的finalize()方法中如果拋出異常,其棧幀軌跡是不會被打印出來的。

《Effective Java中文版 第2版》PDF版下載: http://download.csdn.net/detail/xunzaosiyecao/9745699

作者:jiankunking 出處:http://blog.csdn.net/jiankunking


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲国产成人久久综合一区| 日韩hd视频在线观看| 国产精品久久77777| 在线视频日韩精品| 欧美在线视频观看| 欧美xxxx做受欧美| 欧美日韩激情视频| 91免费国产网站| 欧美精品性视频| 日韩av免费在线观看| 黑人狂躁日本妞一区二区三区| 精品亚洲一区二区三区四区五区| 日韩在线观看网址| 日本91av在线播放| 国产日韩精品在线播放| 国产亚洲激情在线| 最近2019中文字幕mv免费看| 久热国产精品视频| 96精品视频在线| 91亚洲精品久久久| 久久久久北条麻妃免费看| 亚洲字幕在线观看| 97人人爽人人喊人人模波多| 国产精品久久中文| 精品激情国产视频| 最近2019中文字幕mv免费看| 亚洲天堂av在线免费观看| 日韩av电影免费观看高清| 日韩电影中文字幕av| 欧洲美女免费图片一区| 欧美亚州一区二区三区| 日韩精品电影网| 日韩电影免费观看在线| 国产精品视频专区| 色综合伊人色综合网站| 亚洲精品日韩丝袜精品| 精品毛片三在线观看| 少妇av一区二区三区| 亚洲欧美日韩一区二区在线| 欧美乱人伦中文字幕在线| 91久久精品国产91久久性色| 91视频免费在线| 亚洲无线码在线一区观看| 成人国产亚洲精品a区天堂华泰| 日本精品视频在线观看| 欧美日韩国产精品一区二区三区四区| 国产精品中文字幕在线观看| 伊人青青综合网站| 国产欧美在线看| 精品国产区一区二区三区在线观看| 国模精品视频一区二区| 伦伦影院午夜日韩欧美限制| 亚洲性线免费观看视频成熟| 欧美精品xxx| 91免费综合在线| 狠狠色噜噜狠狠狠狠97| 久久精彩免费视频| 成人性生交大片免费看小说| 97视频在线观看免费| 91精品国产自产在线| 久久躁日日躁aaaaxxxx| 欧美限制级电影在线观看| 狠狠躁夜夜躁人人躁婷婷91| 欧美精品九九久久| 久久久久亚洲精品| 欧美福利视频网站| 亚洲肉体裸体xxxx137| 在线精品视频视频中文字幕| 久久中文字幕一区| 2019国产精品自在线拍国产不卡| 91色琪琪电影亚洲精品久久| 91超碰caoporn97人人| 日韩欧美在线视频| 亚洲永久免费观看| 亚洲理论电影网| 欧美激情一级欧美精品| 亚洲免费av电影| 亚洲人成免费电影| 欧美日韩国产一中文字不卡| 国产成人精彩在线视频九色| 欧美成人自拍视频| 欧美一级淫片丝袜脚交| 欧美一级片在线播放| 青青草原成人在线视频| 热久久免费视频精品| 最好看的2019年中文视频| 欧美xxxx做受欧美.88| 欧美高清视频在线播放| 亚洲欧美日韩中文在线| 国产精品人成电影| 久久免费观看视频| 欧美激情乱人伦一区| 久久久久久亚洲精品不卡| 精品国偷自产在线视频| 国产一区二区三区在线观看网站| 欧美高清无遮挡| 成人h片在线播放免费网站| 91色在线观看| 日本国产欧美一区二区三区| 日韩在线不卡视频| 久久琪琪电影院| 国产亚洲精品一区二555| 欧美日韩999| 国产香蕉一区二区三区在线视频| 久久久久久综合网天天| 日韩欧美精品中文字幕| 欧美国产乱视频| 久久99久久亚洲国产| 精品久久久免费| 亚洲片国产一区一级在线观看| 久久69精品久久久久久久电影好| 国产精品久久久久久久久免费| 一本久久综合亚洲鲁鲁| 欧美一级淫片aaaaaaa视频| 欧美成人激情视频免费观看| 国产精品高精视频免费| 在线亚洲欧美视频| 亚洲欧洲视频在线| 91亚洲人电影| 国产一区av在线| 久久久天堂国产精品女人| 日韩视频免费大全中文字幕| 欧美小视频在线观看| www.精品av.com| 国产v综合v亚洲欧美久久| 日韩高清电影免费观看完整| 成人黄色av网站| 亚洲韩国青草视频| 国产自产女人91一区在线观看| 国产精品一区二区女厕厕| 久久国产精品久久久久久| 国产午夜精品一区二区三区| 亚洲精品视频免费在线观看| 成人网欧美在线视频| 成人在线免费观看视视频| 欧美精品生活片| 欧美中文字幕视频在线观看| 亚洲新中文字幕| 欧美一级视频在线观看| 国产精品自拍小视频| 国产中文字幕日韩| 欧美国产日本高清在线| 欧美另类69精品久久久久9999| 国产午夜精品全部视频在线播放| 日韩av免费在线播放| 亚洲精品一区中文字幕乱码| 成人福利网站在线观看11| 一本一本久久a久久精品综合小说| 日韩黄色av网站| 亚洲第一区第一页| 中文字幕av一区二区三区谷原希美| 亚洲精品自在久久| 美女福利视频一区| 九九热在线精品视频| 日韩中文字幕av| 国产精品私拍pans大尺度在线| 成人免费观看49www在线观看| 亚洲韩国青草视频| 亚洲精品中文字幕有码专区| 午夜免费日韩视频| 日韩精品欧美激情| 78m国产成人精品视频| 国产91成人在在线播放| 午夜精品久久久久久久男人的天堂|