日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

《Effective Java》学习笔记 第二章 创建和销毁对象

發布時間:2025/3/21 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《Effective Java》学习笔记 第二章 创建和销毁对象 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

第二章 創建和銷毀對象

何時以及如何創建對象,何時以及如何避免創建對象,如何確保他們能夠適時地銷毀,以及如何管理對象銷毀之前必須進行的各種清理動作。

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

一般在某處獲取一個類的實例最常用的方法是提供一個共有的構造器,還有一種方法,就是提供一個共有的靜態工廠(static factory method),他只是一個返回類的實例的靜態方法。

例:

public static Boolean valueOf(boolean b){return b ? Boolean.TRUE:Boolean.FALSE;} 注意,靜態工廠方法與設計模式中的工廠方法模式不同。類可以通過靜態工廠方法來提供給它的客戶端,而不是通過構造器,提供靜態工廠方法而不是公有的構造器,這樣做具有幾大優勢:
  • 靜態工廠方法,它們有名稱
    例如構造器BIgInteger(int,int,Random)返回的BigInteter可能為素數,如果用名為BigInteger.probablePrime的靜態工廠方法來表示,顯然更為清楚。
  • 不必在每次調用它們的時候都創建一個新的對象

    這使得不可變類可以使用預先構建好的實例,或者將構建好的實例緩存起來,進行重復利用,從而避免常見不必要的重復對象,因為程序經常請求創建相同的對象,那么創建對象的代價會很高。Boolean.valueOf(boolean)方法說明了這項技術。靜態工廠方法也經常用于實現單例模式。
  • 它們可以返回原返回類型的任何子類型的對象

靈活的靜態工廠方法構成了服務提供者框架(Service Provider FrameWork)的基礎,例如JDBC。

對于JDBC,Connection就是它的服務接口,DriverManager.registerDriver是提供者注冊API,DriverManager.getConnection是服務訪問API,Driver就是服務提供者接口。

例,下列簡單的實現包含了一個服務提供者接口和一個默認提供者:

/*** Created by Newtrek on 2017/10/31.* 服務提供者接口*/ public interface Provider { // 提供服務實例,用服務接口返回Service newService(); } /*** Created by Newtrek on 2017/10/31.* 服務接口*/ public interface Service {// TODO: 2017/10/31 服務特有的方法 寫在這兒 } /*** Created by Newtrek on 2017/10/31.*/ public class Services { // 構造保護private Services(){} // provider映射表,保存注冊的Providerprivate static final Map<String ,Provider> providers=new ConcurrentHashMap<>(); // 默認provider的名字public static final String DEFAULT_PROVIDER_NAME="<def>"; // 注冊默認的Providerpublic static void registerDefaultProvider(Provider p){registerProvider(DEFAULT_PROVIDER_NAME,p);} // 注冊providerpublic static void registerProvider(String name,Provider p){providers.put(name,p);}/*** 靜態工廠方法返回Service實例*/public static Service newInstance(){return newInstance(DEFAULT_PROVIDER_NAME);}public static Service newInstance(String name){Provider p = providers.get(name);if (p==null){throw new IllegalArgumentException("No provider registered with name:"+name);}return p.newService();} }
  • 在創建參數化類型實例的時候,它們是代碼變得更加簡潔

例:假設HashMap提供了這個靜態工廠

public static <K,V> HashMap<K,V> newInstance(){return new HashMap<K,V>();}

那么就可以用下面簡潔的代碼獲取實例了。

Map<String,List<String>> m=HashMap.newInstance();

把這些方法放在自己的工具類中是很實用的。不過現在java7,java8已經實現了HashMap構造的類型參數推測

缺點

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

    • 在API文檔中,它們沒有像構造器那樣在API文檔中明確標識出來,因為,對于提供了靜態工廠方法二不是構造器的類來說,要想查明如何實例化一個類,這是非常困難的。可以通過在類或者接口注釋中關注靜態工廠,并遵守標準的命名習慣,可以彌補這一劣勢。下面是靜態工廠方法的一些慣用名稱。

      • valueOf:實際上是類型轉換方法。
      • of:valueOf的一種更為簡潔的代替
      • getInstance:返回的實例是通過方法的參數來描述的,但是不能夠說與參數具有同樣的值。對于Singleton來說,該方法沒有參數,并返回唯一的實例。
      • newInstance:像getInstance一樣,但newInstance能夠確保返回的每個實例都與所有其它實例不同。
      • getType:像getInstance一樣,但是在工廠方法處于不同的類中的時候使用。Type表示工廠方法所返回的對象類型。
      • newType:像newInstance一樣,但是在工廠方法處于不同的類中的時候使用,Type表示工廠方法所返回的對象類型。
簡而言之,靜態工廠方法和公有構造器都各有用處,我們需要理解他們各自的長處。靜態工廠通常更加合適,因此切忌第一反應就是提供公有的構造器,而不先考慮靜態工廠。

2.遇到多個構造器參數時要考慮用構建器

這個就是Builder設計模式

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

這個是單例模式的注意事項,選擇最好的單例模式實現

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

有時候需要編寫一些只包含靜態方法和靜態域的類,這些類的名聲很不好,因為有些人在面向對象的語言中濫用這樣的類來編寫過程化的程序,盡管如此,他們也確實有它們的好處,比如常見的工具類java.lang.Math等,都是這樣。方正這樣不可以實例化的類,最好把他的構造器設置為私有。

例如:

public class UtilityClass{private UtilityClass(){throw new AssertionError();} }

5.避免創建不必要的對象

一般來說,最好能重用對象而不是再每次需要的時候就創建一個相同功能的新對象,如果對象是不可變的,他就始終可以被重用。
簡單的例子:字符串

String s = new String("stringtest");//不要這樣做,因為該語句每次執行的時候都會創建一個新的String實例,沒必要 // 改進后的版本,這個版本只用了一個String實例,而不是每次執行的時候都創建一個新的實例。對于再同一臺虛擬機中運行的代碼,只要它們包含相同的字符串自字面常量,該對象就可以被重用。 String s = "stringtest";

對于同時提供了靜態方法和構造器方法的不可變類,通常可以使用靜態工廠方法而不是構造器,以避免創建不必要的對象。

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

也不要錯誤地認為本條目暗示著“創建對象的代價非常昂貴,我們應該盡可能地避免創建對象”,相反,由于小對象地構造器制作很少量地顯示工作,所以,小對象地創建和回收動作是非常廉價地。

通過維護自己的對象池來避免創建對象比不是一種好的做法,除非池中的對象是非常重量級的,一般數據庫連接池常用。

6 消除過期的對象引用

不要以為Java有垃圾回收機制,能自動管理內存,自動回收垃圾,就可以不管了,其實不然。
內存泄漏的例子

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

這段程序并沒有明顯的錯誤,如果是棧先是增長,然后再收縮,那么,從棧中彈出來的對象將不會被當作垃圾回收,因為里面的數組里引用著它,棧內部維護著這些對象的過期引用,過期引用就是指永遠也不會再被解除的引用。

這類問題的修復方法很簡單:一旦對象引用已經過期,只需清空這些應用即可。

沒必要對于每一個對象引用,一旦程序不再用到它,就把它清空。清空對象引用應該是一種例外,而不是一種規范行為,消除過期引用最好的辦法是讓包含該對象的變量結束其生命周期。一般而言,只要類是自己管理內存,程序員就應該警惕內存泄漏問題,一旦元素被釋放掉,則該元素中包含的任何對象引用都應該被清空。

內存泄漏的另一個常見來源是緩存,一旦你把對象放在緩存中,他就很容易被遺忘掉,從而使得它不再有用之后很長一段時間內仍然留在緩存中。可以用WeakHashMap

內存泄漏的第三個常見來源是監聽器和其他回掉,一般都要取消注冊,或者用弱引用

內存泄漏通常不會表現成明顯的失敗,所以他們可以再一個系統中存在很多年,往往通過仔細檢查代碼,借助于Heap刨析工具才能發現內存泄漏問題。

7 避免使用終結方法

終結方法(finalizer)通常是不可預測的,也是很危險的,一般情況下是不必要的。

C++的析構器是回收一個對象所占用資源的常規方法,是構造器所必須的對應物,也可以用來回收其他的非內存資源,而在Java中,一般用try-finally塊來完成類似的工作

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的《Effective Java》学习笔记 第二章 创建和销毁对象的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。