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

首頁 > 編程 > Java > 正文

Effective Java讀書筆記三:創建和銷毀對象

2019-11-11 04:06:09
字體:
來源:轉載
供稿:網友

第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>(); } 1234567812345678

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

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

常用的靜態工廠名稱: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); } 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455561234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556

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

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

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

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

這樣的方式主要優勢在于簡潔高效,使用者很快就能判定當前類為單實例類,在調用時直接操作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() { ... } } 123456123456

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

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

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

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

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

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

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

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

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

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

String s = new String(“stringette”); 11

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

String s = “stringette”; 11

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

對于同時提供了靜態工廠方法和構造器的不可變類,通??梢允褂渺o態工廠方法而不是構造器,以避免創建不必要的對象。 例如,靜態工廠方法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);}12345671234567

這段程序算出的答案是正確的,但是比實際情況要更慢一些,只因為打錯了一個字符。變量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); } } 123456789101112131415161718192021123456789101112131415161718192021

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

修改方式如下:

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

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

from: http://blog.csdn.net/jiankunking/article/details/54862672


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲第一av网| 久久久www成人免费精品| 狠狠色噜噜狠狠狠狠97| www.美女亚洲精品| 最好看的2019的中文字幕视频| 国模精品一区二区三区色天香| 一区三区二区视频| 久久久久久久久久av| 成人国产精品免费视频| 九九热这里只有在线精品视| 日韩精品中文字幕久久臀| 久久精品一本久久99精品| 成人黄色片网站| 91精品国产高清自在线看超| 国产日韩欧美在线观看| 国产福利精品视频| 欧美日韩一区二区免费视频| 精品久久久久久亚洲国产300| 亚洲色图美腿丝袜| 亚洲第一页在线| 国产精品草莓在线免费观看| 亚洲午夜久久久影院| 欧美电影免费观看高清| 欧美大片免费看| 国产精品美乳在线观看| 亚洲精品一区二区久| 欧美性高潮在线| 一区二区三区www| 欧美做爰性生交视频| 成人黄色免费网站在线观看| 亚州欧美日韩中文视频| 色午夜这里只有精品| 久久久国产成人精品| 久久精品视频在线| 日韩欧美在线第一页| 成人国产精品色哟哟| 2019精品视频| 中文字幕日韩av综合精品| 国产成人综合精品在线| 亚洲自拍av在线| 欧美黄色片在线观看| 亚洲夜晚福利在线观看| 欧美猛交ⅹxxx乱大交视频| 亚洲xxx视频| 97精品国产97久久久久久免费| 高清欧美性猛交xxxx黑人猛交| 欧美一区二区三区艳史| 国产91色在线播放| 国产精品热视频| 91香蕉电影院| 国产精品国产自产拍高清av水多| 欧美高清自拍一区| 欧美亚洲在线播放| 久久久久一本一区二区青青蜜月| 夜夜嗨av色一区二区不卡| 亚洲女成人图区| 在线免费观看羞羞视频一区二区| 国产精品video| 欧美日本国产在线| 日韩精品视频免费在线观看| 这里只有精品视频| 国产精品6699| 成人精品一区二区三区电影免费| 国产精品手机播放| 按摩亚洲人久久| 国产v综合v亚洲欧美久久| 国产精品视频一区二区三区四| 97视频在线观看免费高清完整版在线观看| 成人免费视频网址| 欧美乱人伦中文字幕在线| 国产精品一区二区久久国产| 国产欧美一区二区三区四区| 日韩在线视频线视频免费网站| 欧美高清无遮挡| 亚洲精品456在线播放狼人| 久久久精品中文字幕| 亚洲欧美福利视频| 亚洲成人国产精品| 亚洲一区二区福利| 欧美亚洲日本黄色| 国外日韩电影在线观看| 国内外成人免费激情在线视频网站| 97涩涩爰在线观看亚洲| 欧美性猛交xxxx免费看| 麻豆乱码国产一区二区三区| 另类色图亚洲色图| 欧美中文字幕视频| 国产女人精品视频| 久久久久久com| 亚洲丁香久久久| 亚洲最大激情中文字幕| 亚洲第一区中文99精品| 久久免费视频在线| 亚洲图中文字幕| 成人黄色片在线| 日韩黄色在线免费观看| 欧美日韩中文字幕| 久久精品国产96久久久香蕉| 中文字幕日韩欧美在线| 亚洲自拍小视频免费观看| 欧美性极品xxxx娇小| 欧美中文字幕在线视频| 精品免费在线视频| 亚洲在线一区二区| 久久精品亚洲94久久精品| 97在线精品国自产拍中文| 亚洲国产精品国自产拍av秋霞| 亚洲剧情一区二区| 欧美在线www| 国产精品欧美一区二区三区奶水| 日韩av网址在线观看| 高清欧美一区二区三区| 国产精品三级久久久久久电影| 日产日韩在线亚洲欧美| 日韩欧美精品免费在线| 精品免费在线视频| 亚洲精品视频播放| 中日韩美女免费视频网站在线观看| 亚洲有声小说3d| 久久综合九色九九| 2021国产精品视频| 精品国偷自产在线视频99| 欧美黑人性猛交| 亚洲一品av免费观看| 亚洲精品免费在线视频| 欧美日韩中文字幕综合视频| 国产中文字幕亚洲| 日韩高清人体午夜| 国产精品久久久久久久久| 国产成人精品免高潮费视频| 一区二区欧美激情| 国产欧美精品一区二区三区-老狼| 中文字幕成人精品久久不卡| 亚洲黄色片网站| 欧美性色19p| 日韩中文字幕在线看| 视频一区视频二区国产精品| 中文字幕最新精品| 久久精品电影一区二区| 91精品国产综合久久香蕉| 日本一区二区在线播放| 欧美黑人xxxⅹ高潮交| 欧美黑人xxxⅹ高潮交| 久久韩剧网电视剧| 91精品国产亚洲| 精品一区二区三区四区| 成人美女免费网站视频| 97久久国产精品| 亚洲人免费视频| 日韩高清欧美高清| 国产精品网站入口| 91精品国产乱码久久久久久久久| 欧美一级视频在线观看| 成人av在线网址| 国产精品视频地址| 欧美视频裸体精品| 亚洲奶大毛多的老太婆| 热久久免费国产视频| 国产精品视频一区二区三区四| 国产一区二区三区直播精品电影| 91老司机在线| 国产综合视频在线观看| 亚洲一区二区在线播放| 成人性教育视频在线观看|