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

首頁 > 編程 > Java > 正文

Effective Java讀書筆記——第二章 創建和銷毀對象

2019-11-06 06:34:14
字體:
來源:轉載
供稿:網友

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

每個類都可以提供一個公有的靜態工廠方法(static factory method),這就是一個返回類的實例的靜態方法:

public static Boolean valueOf(boolean b) { return b ? Boolean.TRUE : Boolean.FALSE; }

上面的方法將boolean基本類型值轉換成一個Boolean對象的引用,即Boolean類型的一個實例。

只公有的靜態方法而不是構造器來提供類的一個實例有如下幾點優勢:

靜態工廠方法可以做到見名知意:調用構造器BigInteger( int, int, Random )可能返回一個素數,但是在沒有注釋的情況下很難得知這個構造器的作用,不過使用BigInteger.PRobablePrime的驚濤方法就顯得更為清楚。

不必每次調用靜態工廠方法時都創建一個新的實例:這可以增加復用的幾率,減少內存的開銷。對于大型對象來說可以大大提高性能。這種不必每次都創建一個新的實例的類叫做實例受控的類(instance-controlled),這種類型確保該類是一個單例類(Singleton)不可直接實例化的類;另外,單例類還保證了a==b 與 a.equals(b)為true 互為充要條件,這樣的話,可以使用==操作符代替equals方法,可以提升效率。

靜態工廠方法可以返回原來類型的任意子類型,靈活性大大提高。下面這個栗子中,Provider負責提供Service的實現實例,而所有的Provider都被保存于靜態的Map

public interface Service {//Service中的具體方法}public interface Provider { Service newService();}//負責保存Service的實例,獲取、注冊Service實例public class Services { private Services() { } private static final Map<String,Provider> providers = new ConcurrentHashMap<>(); public static final String DEFAULT_PROVIDER_NAME = "<def>"; //注冊一個默認的Provider public static void registerDefaulrProvider(Provider p){ registerProvider(DEFAULT_PROVIDER_NAME, p );} public static void registerProvier(String name, Provider p) { providers.put(name,p);} //客戶端調用的APIpublic static Service newInstance() { return newInstance(DEFAULT_PROVEIDER_NAME);}public static service newInstance(String name) {Provider p = providers.get(name);if(p == null){throw new IllegalArgumentExecption("No provider registerd with name: " + name);}return p.newService();}}靜態工廠方法使得實例化變得更加簡潔:首先,使用常規的構造器形式實例化Map<String, List<String>> m = new HashMap<String,List<String>>;;而如果HashMap提供了靜態方法 public static <k, v> HashMap<K,V> newInstance() { return new HashMap<K , V>();

}

那么在調用端就會變得簡單:

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

第2條:遇到多個構造器參數時考慮使用構建器

一句話: 重疊構造器可行。但是當有許多參數的時候??蛻舳舜a會很難編寫,并且仍較難以閱讀。若讀者相紙到那些值是啥意思,必須仔細了解這些參數的意義。這很容易導致錯誤:若不小心導致了錯誤,編譯器也不會報錯,但在運行時會出現錯誤行為。

另一種方式是使用javaBeans的方式。這種方式可讀性強,但JavaBeans存在一個先天的不足,那就是初始化一個對象的過程并不是一步完成,而要分成多次,若漏掉某個參數的初始化,那么查錯會變得困難。

第三中方式兼顧了第一章方式的安全性和第二種方式的可讀性。即Builder模式。不直接生成想要的對象,而是讓客戶端利用所有必要的參數調用構造器,得到一個builder對象。然后客戶端在builder對象上調用類似于setter的方法,來設置每個相關的可選參數。最后,客戶端調用午餐的build方法來生成不可變的對象。這個builder是它構建的類的靜態成員類:

public 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 carbohydrate = 0; private int sodium = 0; //Builder構造方法 public Builder(int servingSize, int servings) { this.servingSize = servingSize; this.servidngs = servings; } public Builder calories(int val) { calories = val; } public Builder fat(int val) { fat = val; return this; } public Builder carbohvdrate(int val) { carbohvdrate = 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; }}

那么客戶端代碼就可以寫成:

NutritionFacts cocaCola = new NutritionFacts.Builder(240,8).calories(100).fat(0).sodium(35).build();

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

Singleton通常被用來代表那些本質上唯一的系統組件

在JDK1.5之前,一般定義一個私有的構造器并導出公有的靜態成員:

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

這種方式有一個問題:享有特權的客戶端可以借助accessibleObject.setAccessible方法,通過反射調用私有的構造器。

在JDK1.5 之前 還有一種方式實現單例類,即靜態工廠方法:

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

JDK1.5版本以后,可以使用單元素的枚舉類型創建單例類:

public enum Elvis { INSTANCE;}...

這種方式目前是實現單例類的最佳方式。

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

略…

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

String s = new String("stringette");

若在一個循環中每次都創建一個String實例,是完全不必要的,實際上只需要這樣:

String s = "stringette";

這保證了在同一臺虛擬機內,只要包含相同的字符串字面常量,該對象就會被重用。

自動裝箱和拆箱也暗含著創建不必要的對象:

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

該循環每執行一遍,都會實例化一個Long的實例,這樣相當耗費內存,指引自動裝箱的緣故,只需要將Long 改為long。

有些對象的初始化很耗費資源,如Calendar類,對于這種類,根據實際的應用場合,只需要實例化一次,所以可以把該類的實例化放在靜態初始化塊中。

首先舉個反例:

public class Person { private final Date birthDate; //錯誤的寫法 public boolean isBatyBoomer() { Canlendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); gmtCal.set(1946,Calendar.JANUARY,1,0,0,0); Date boomStart = gmtCal.getTime(); gmtCal.set(1965,Calendar.JANUARY,1,0,0,0); Date boomEnd = gmtCal.getTime(); return birthDate.compareTo(boomStart) >= 0 && birthDate.compareTo(boomEnd) < 0; }}

每調用一次方法,都新建一個Calendar,一個TimeZone,兩個Date對象,這是不必要的。

在靜態初始化塊中初始化Calendar,避免其重復創建:

public class Person { private final Date birthDate; private static final Date BOOM_START; private static final Date BOOM_END; static { Calendar gmtCal = Calendar.getInstance(TimeZone.getImeZone("GMT")); gmtCal.set(1946, Calendar.JANUARY,1,0,0,0); BOOM_START = gmtCal.getTime(); gmtCal.set(1965,Calendar.JANUARY,1,0,0,0); BOOM_END = gmtCal.getTime(); } public boolean isBabyBoomer() { return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo(BOOM_END) < 0; }}

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

public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack(){ elements = new Objects[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.copyOf(elements, 2 * size + 1); } }}

上述代碼中存在內存泄漏的風險,當元素從數組中彈棧的時候,我們只是單純地將數組的范圍減少1,但是并沒有把該范圍之外的數組中引用的對象釋放掉,這就造成了過期的引用無法被釋放的問題,從而造成了內存泄漏。

解決辦法是,將那些過期的引用置空:

public Object pop() { if(size == 0) { throw new EmptyStackEception(); } Object result = elements[--size]; elements[size] = null; return result;}

這種做法的另一個好處是,當數組中過期的引用被錯誤的引用時,會拋出NullPointerExecption異常。

內存泄漏還有一種常見的來源,就是緩存——一旦把對象引用放到緩存中,它就很容易被遺忘掉,從而使得它不再有用之后很長一段時間仍然留在緩存中。

推薦幾篇有關內存泄漏的文章,值得一讀~: 1、內存泄露從入門到精通三部曲之基礎知識篇 2、內存泄露從入門到精通三部曲之常見原因與用戶實踐 3、內存泄露從入門到精通三部曲之排查方法篇


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

總結起來就一句:盡量避免使用終結方法。

原因是:終結方法不能保證會被及時地執行——從一個對象變得不可到達(即沒有任何引用再只想這個對象)到它的終結方法被執行(finalize()執行),這段時間是任意長的,不可控的;第二,不使用finialize()作為回收資源的方式,是因為不同的JVM回收算法實現起來大相徑庭,時間不一樣;第三,finialize()方法根本不保證會被執行。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美综合第一页| 日本久久久久久| 欧美日韩福利视频| 久久久免费精品| 最近2019年日本中文免费字幕| 精品久久久视频| 成人av在线网址| 国产精品一区二区久久久| 日韩小视频在线观看| 欧美激情在线有限公司| 国产精品在线看| 亚洲精品色婷婷福利天堂| 久久精品亚洲94久久精品| 国产视频在线一区二区| 欧美视频第一页| 91精品国产成人| 狠狠色噜噜狠狠狠狠97| 国产精品黄色影片导航在线观看| 成人福利视频网| 亚洲成色777777在线观看影院| 欧美视频第一页| 在线a欧美视频| 欧美色视频日本版| 丁香五六月婷婷久久激情| 亚洲视频电影图片偷拍一区| 久久精品成人一区二区三区| 国产视频精品免费播放| 日本精品免费观看| 国内精品久久久久| 久久高清视频免费| 欧美有码在线视频| 亚洲欧美日韩中文视频| 精品国产精品三级精品av网址| 日韩av在线免费观看一区| 国产在线观看精品一区二区三区| 色噜噜狠狠狠综合曰曰曰| 亚洲国产日韩欧美综合久久| 成人免费午夜电影| 国产精品影院在线观看| 日韩成人黄色av| 性欧美xxxx视频在线观看| 国产视频在线一区二区| 久久久久久久久久国产| 亚洲欧美变态国产另类| 国产精品欧美一区二区| 久久电影一区二区| 欧美成人精品h版在线观看| 黄网动漫久久久| 琪琪亚洲精品午夜在线| 欧美一区二区色| 隔壁老王国产在线精品| 91精品国产91久久久久久吃药| 国产精品入口尤物| 亚洲精品美女在线观看| 国产成人精品日本亚洲| 色妞一区二区三区| 中文字幕精品网| 亚洲开心激情网| 欧美三级欧美成人高清www| 欧美在线一级视频| 91tv亚洲精品香蕉国产一区7ujn| 久久久亚洲天堂| 色爱精品视频一区| 日韩欧美综合在线视频| 国产精品成人va在线观看| 欧美xxxx做受欧美| 欧美成人午夜视频| 亚洲午夜性刺激影院| 欧美午夜精品久久久久久人妖| 九色精品免费永久在线| 日韩欧美精品网站| 全球成人中文在线| 日本欧美一二三区| 日韩激情片免费| 亚洲护士老师的毛茸茸最新章节| 亚洲大胆人体在线| 日韩精品亚洲视频| 日韩视频中文字幕| 97超级碰在线看视频免费在线看| 日韩美女视频中文字幕| 亚洲一区999| 欧美影院在线播放| 亚洲欧洲一区二区三区久久| 日韩亚洲国产中文字幕| 久久久久久久影视| 久久久久久国产精品三级玉女聊斋| 日韩大片免费观看视频播放| 亚洲精品久久久久久下一站| 欧美高清理论片| 国产精品中文久久久久久久| 狠狠躁夜夜躁人人爽超碰91| 高潮白浆女日韩av免费看| 久久久免费精品| 中文欧美日本在线资源| 国产精品自在线| 日韩av快播网址| 欧美午夜美女看片| 韩国福利视频一区| 日本精品性网站在线观看| 亚洲精品女av网站| 国产亚洲精品一区二区| 久久久久久久久久久免费精品| 国产成人精品免高潮在线观看| 国产国语videosex另类| 一本大道香蕉久在线播放29| 亚洲国产欧美一区二区丝袜黑人| 日本一区二区三区四区视频| 欧美日韩精品中文字幕| 97**国产露脸精品国产| 日韩精品高清视频| 亚洲男人天堂2023| 青青在线视频一区二区三区| 日本精品va在线观看| 成人久久一区二区| 色综合久久久888| 成人av在线网址| 欧美又大又粗又长| 黑人欧美xxxx| 91视频-88av| 日韩资源在线观看| 国色天香2019中文字幕在线观看| 欧美丰满少妇xxxxx做受| 成人美女av在线直播| 国语自产精品视频在线看| 欧美激情精品久久久久久久变态| 欧美性猛交xxxx乱大交3| 美女av一区二区| 亚洲精品国产品国语在线| 日本久久亚洲电影| 日韩美女主播视频| 欧美一性一乱一交一视频| 2021国产精品视频| 亚洲精品国精品久久99热一| 国产精品成人aaaaa网站| 亚洲成人三级在线| www.日韩不卡电影av| 日韩乱码在线视频| 成人啪啪免费看| 欧美精品中文字幕一区| 久久99热这里只有精品国产| 亚洲理论片在线观看| 国产精品亚洲激情| 国产精品成人久久久久| 91视频8mav| 亚洲激情国产精品| 亚洲国产精品久久| 国产精品国内视频| 欧美另类精品xxxx孕妇| 国产综合在线看| 国产精品一区二区电影| 国产精品444| 色妞色视频一区二区三区四区| 日本道色综合久久影院| 成人网在线免费看| 91精品免费久久久久久久久| 久久中文字幕在线| 亚洲一级黄色av| 欧美激情精品久久久久久免费印度| 精品久久久久久亚洲国产300| 精品国产欧美一区二区五十路| 亚洲第一色中文字幕| 亚洲一品av免费观看| 精品无人区乱码1区2区3区在线| 亚洲精品国产拍免费91在线|