《Effective Java》之 對象的創(chuàng)建和銷毀

圖片來自網(wǎng)絡

對象的創(chuàng)建和銷毀

第一條 用靜態(tài)工廠方法來代替構造器

類除了可以通過構造器來實例化之外,還可以通過靜態(tài)的工廠方法(newInstance)

優(yōu)勢

1. 他們有名稱

比如一個Apple類摩幔,你想獲得一個紅蘋果和綠蘋果的實例榄檬,Apple.newRedInstance()Apple.newGreenInstance()Apple(red)Apple(green)看上去要更能突出他們之間的區(qū)別

2. 不必在每次調(diào)用的時候都創(chuàng)建一個新對象

class Apple{
     private Apple apple;    
     private Apple();
    newInstance(){
           return apple ==null ?new Apple : apple;
    }
}

單例模式的簡單寫法,單例模式的有各種好處,比如不用重復創(chuàng)建對象,可以用==來代替equals方法等等之類的我就不多說神馬了。

3. 可以返回原返回類型的任何子類型對象

這種時候我們在返回對象的類時就有了更大的靈活性寝姿,甚至于我們在編寫該靜態(tài)方法的時候這個類是可以不存在的。書上管這個叫服務提供者框架(Service Provicer Framework)划滋。 例如JDBC 的API就是一個很好的例子饵筑。Connection是他的服務接口,DriverManager.registerDriver 是提供者的API处坪,DriverManager.getConnection是服務訪問的API根资,Driver就是服務提供者接口。適配器模式也是這種框架的一種變體同窘。

// 服務提供者框架簡易Demo
// 服務類的接口
public interface Service{
    // 具體需要實現(xiàn)的服務方法
}
// 服務提供者的接口
public interface Provider{
    Service newService();
}
// Service 注冊和調(diào)用的類
public class Services{
    private Services();    // 防止實例化
    // Service 名字跟服務的Map
    private static final Map<String,Provider> providers = new ConcurrentHashMap<String , Provider>( );
    public static final String DEFAULT_PROVIDER_NAME = "<dev>";
    // 服務提供者注冊的API
    public static void registerDefaultProvider(Provider p){
         registerProvider(DEFAULT_PROVIDER_NAME ,p); 
    }
    public static void registerDefaultProvider(String name ,Provider p){
         providers.put(name ,p); 
    }
//  獲取服務接口
public static Service newInstance(){
    return newInstance(DEFAULT_PROVIDER_NAME);
}
publicstatic Service newInstance(String name ){
    Provider p = providers.get(name);
    if(p== null)
            throw new IllegalArgumentException("這個服務者沒有注冊");
    return p.newService();
}

適配器模式的簡單例子玄帕。

4. 實例化參數(shù)類型時更簡單

比如

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

隨著參數(shù)越來越長,越來越復雜想邦,代碼就越來越丑了裤纹。
這個時候如果有這個方法

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

那我們只要這樣寫就好了Map<String,List<String>> m = HshMap.newInstance();,代碼就簡潔了好多。目前(jdk 1.8.0_73)官方并沒有實現(xiàn)這樣的方法丧没,可以放在自己的工具類中體現(xiàn)自己的逼格鹰椒。

缺點

  • 如果類不含public 或者protect 的構造方法則不能被實例化
    是缺點也是優(yōu)點,關鍵看你腫么用吧呕童。漆际。。
  • 不能在java doc中有什么體現(xiàn)拉庵。
    java doc認識構造方法灿椅,會重點標識出來套蒂,但是靜態(tài)方法不會钞支,所以用起來找api會麻煩。

第二條 當構造方法有多個可選參數(shù)的時候考慮用構造器

當實例化一個類有很多可選參數(shù)的時候操刀,有如下的幾種方法

創(chuàng)建多個構造器

優(yōu)點: 能用
缺點:寫起來容易錯烁挟,參數(shù)的順序啊神馬的記起來容易錯

用JavaBean 的getter 和setter 模式

優(yōu)點:寫的時候不容易出錯
缺點:線程不安全

使用構造器模式

優(yōu)點:使代碼簡單好些,而且看上去很有逼格
缺點:增加了一些開銷
拿一個蘋果類舉例

class Apple{
    private String color;
    private String size;
    private String weight;
    private String price;
    
    public static class Builder{
        private String color;
        private String size;
        private String weight;
        
        public Builder color(String color){
            this.color = color;
            return this;
        }
        public Builder size(String size){
            this.size = size;
            return this;
        }
        public Builder weight(String weight){
            this.weight = weight;
            return this;
        }
        public Apple bulid(){
            return new Apple(this);
        }
    }
    
    private Apple(Builder bulider){
        this.color = bulider.color;
        this.size = bulider.size;
        this.weight = bulider.weight;
    };
}

然后就可以通過下面的方式來實例化一個蘋果

Apple apple = new Apple.Builder().color("red").size("100").weight("100").bulid(); 

這樣逼格滿滿的代碼就出來了骨坑。在可選參數(shù)很多的時候選擇這種寫法是種很不錯的選擇撼嗓。

第三條 單例的三種寫法和注意事項

原翻譯 使用枚舉增強類的單例屬性

單例模式的各種好處就不說柬采,這條講了單例的三種寫法和注意事項

寫法一

class Apple{
    public static Apple INSTANCE = new Apple();
    // someThing
    private Apple(){
    };
} 

寫法二

class Apple{
    private static Apple INSTANCE = new Apple();
    // someThing
    private Apple(){
    };
    public static Apple newInstance(){
        return INSTANCE;
    }
} 

*** 注意事項 ***

  1. AccessibleObject.setAccessible 可以通過反射調(diào)用私有的構造方法。在構造器加上第二次實例化拋異常的邏輯可以防范這種攻擊且警。

  2. 如果單例的類為了可序列化而繼承了 Serializable 接口粉捻,那么為了防止類在反序列化的時候被偷偷的實例化,可以在類中加入如下代碼

    private Object readResolve() {
        return INSTANCE;
    } 

寫法三 使用枚舉實現(xiàn)單例

enum Apple{
    INSTANCE;
}
  • 優(yōu)點
    簡單明了斑芜,不僅能防止因為反序列而重新創(chuàng)建對象肩刃,又是線程安全的,簡直逼格滿滿
  • 缺點
    這是JDK1.5之后的新特性杏头,這么寫可能有些人會看不懂(怪我咯j╮(╯_╰)╭)盈包。

第4條 通過私有化構造器使單例類更加單例

有些工具類我們可能不希望它被實例化,可以使用如下代碼

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

這樣一來醇王,AppleUtils(和他的子類)就不能被實例化了呢燥。

第5條 避免創(chuàng)建不必要的對象

對象么能少創(chuàng)建就少創(chuàng)建,這條主要講了如何更少的創(chuàng)建對象

  • 比如不要寫 String s = new String("Don't do this"); 這樣的代碼(因為這里創(chuàng)建了兩個String 對象)
  • 對于有靜態(tài)工廠方法和構造器的不可變類寓娩,盡量使用靜態(tài)工廠方法
  • 對象能重用的就盡量重用
    明顯能重用那肯定是要重用的叛氨,有些不明顯的比如像Map接口的KeySet方法每次返回的Set實例這種也是考慮用一個對象減少實例化的
  • 使用基本數(shù)據(jù)類型時防止程序自從裝箱
    例如如下代碼
Long sum =0L;
for (int i = 0; i < Integer.MAX_VALUE; i++) {
sum +=i;
}
System.out.println(sum); 

這段代碼在我機器上的運行時間為

Long 的運行時間

但是如果把Long sum 換成long sum

long 的運行時間

可以看到時間從6886ms變成了781ms,效率大大的優(yōu)化了。

第六條 避免內(nèi)存泄露的幾點建議

原翻譯:消除過期的對象引用

  • 警惕自己管理內(nèi)存的類
  • 警惕讓不用的對象留在緩存中
    wakHashMap 和LinkedHashMap 可以一定程度解決這個問題
  • 警惕監(jiān)聽器和其他回調(diào)
    最好只保存他們的若引用根暑,例如只將他們保存成WeakHashMap中的鍵

第七條 避免使用終結(finalizer)方法

  • finalizer方法并不能保證被及時的執(zhí)行
    從對象不可到達到它的finalizer方法被執(zhí)行力试,其中的這段時間是不好估計的。
  • finalizer方法并不能保證被正確的執(zhí)行
    不同的JVM實現(xiàn)中finalizer的效果是不同的排嫌。
  • finalizer方法并不能保證被執(zhí)行
    當一個程序被終止的時候畸裳,某些已經(jīng)無法訪問的對象上的終結方法沒有被執(zhí)行也是有可能的。
  • finalizer 有一個非常嚴重的性能損失
    Effective Java的作者說他試了下淳地,真的有很嚴重的性能損失怖糊。
    所以最好有顯示的終止方法,向InputStream颇象、OutputStream``的close方法伍伤,java.util.Timer中的cancel```方法之類的。

總結

這一章主要講了對象的創(chuàng)建和銷毀時候需要注意的一些點遣钳。有些代碼真的是使人豁然開朗扰魂,瞬間逼格滿滿。期待第二章的學習蕴茴,F(xiàn)ighting~

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末劝评,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子倦淀,更是在濱河造成了極大的恐慌蒋畜,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件撞叽,死亡現(xiàn)場離奇詭異姻成,居然都是意外死亡插龄,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門科展,熙熙樓的掌柜王于貴愁眉苦臉地迎上來均牢,“玉大人,你說我怎么就攤上這事才睹∨虼Γ” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵砂竖,是天一觀的道長真椿。 經(jīng)常有香客問我,道長乎澄,這世上最難降的妖魔是什么突硝? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮置济,結果婚禮上解恰,老公的妹妹穿的比我還像新娘。我一直安慰自己浙于,他們只是感情好护盈,可當我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著羞酗,像睡著了一般腐宋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上檀轨,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天胸竞,我揣著相機與錄音,去河邊找鬼参萄。 笑死卫枝,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的讹挎。 我是一名探鬼主播校赤,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼筒溃!你這毒婦竟也來了马篮?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤铡羡,失蹤者是張志新(化名)和其女友劉穎积蔚,沒想到半個月后意鲸,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烦周,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡尽爆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了读慎。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片漱贱。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖夭委,靈堂內(nèi)的尸體忽然破棺而出幅狮,到底是詐尸還是另有隱情,我是刑警寧澤崇摄,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站慌烧,受9級特大地震影響逐抑,放射性物質發(fā)生泄漏屹蚊。R本人自食惡果不足惜厕氨,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望汹粤。 院中可真熱鬧命斧,春花似錦、人聲如沸嘱兼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芹壕。三九已至胃惜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間哪雕,已是汗流浹背船殉。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留斯嚎,地道東北人利虫。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像堡僻,于是被迫代替她去往敵國和親糠惫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容