国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

Effective Java

2019-11-14 21:45:18
字體:
來源:轉載
供稿:網(wǎng)友
Effective java - 避免不必要的對象

通常,我們更喜歡重用一個對象而不是重新創(chuàng)建一個。如果對象是不可變的,它就始終可以被重用。

下面是一個反面例子:

String s = new String("stringette");

該語句每次執(zhí)行時都創(chuàng)建一個新的實例。String構造器中的參數(shù)"stringette"本身是一個實例,功能方面等同于那些通過構造器創(chuàng)建的對象。如果這種語句放到循環(huán)里,效果會變得更糟。

于是我們只需要:

String s = "stringette";

這樣就永遠是同一個string實例,并且可以保證同一個VM中會重用相同字符串字面量的對象。(the object will be reused by any other code running in the same vitual machine that happens to contain the same string literal.)

如果類中同時提供了靜態(tài)工廠方法和構造器,客戶端通常可以使用靜態(tài)工廠方法來防止創(chuàng)建不必要的對象。比如java.lang.Boolean:

public static final Boolean TRUE = new Boolean(true);   public static final Boolean FALSE = new Boolean(false);    public static Boolean valueOf(boolean b) {    return (b ? TRUE : FALSE);}

而在構造器的javadoc中也做了相應的說明:

    /**     * Allocates a {@code Boolean} object rePResenting the     * {@code value} argument.     *     * <p><b>Note: It is rarely appropriate to use this constructor.     * Unless a <i>new</i> instance is required, the static factory     * {@link #valueOf(boolean)} is generally a better choice. It is     * likely to yield significantly better space and time performance.</b>     *     * @param   value   the value of the {@code Boolean}.     */    public Boolean(boolean value) {        this.value = value;    }

除了重用不可變的對象,我們也可以重用那些不會再有變化的可變對象。(Also use mutable object if you know they won't be modified.)

下面是一個反面例子,檢查某人是否出生于生育高峰期(1946~1964):

import java.util.Calendar;import java.util.Date;import java.util.TimeZone; public class Person {    private final Date birthDate;     public Person(Date birthDate) {        // Defensive copy - see Item 39        this.birthDate = new Date(birthDate.getTime());    }     // Other fields, methods omitted     // DON'T DO THIS!    public boolean isBabyBoomer() {        // Unnecessary allocation of expensive object        Calendar 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.getInstance和兩次getTime,這些都會創(chuàng)建新的實例:

    public static Calendar getInstance(TimeZone zone,Locale aLocale){        return createCalendar(zone, aLocale);    }      private static Calendar createCalendar(TimeZone zone,Locale aLocale){        Calendar cal = null;         String caltype = aLocale.getUnicodeLocaleType("ca");        if (caltype == null) {            // Calendar type is not specified.            // If the specified locale is a Thai locale,            // returns a BuddhistCalendar instance.            if ("th".equals(aLocale.getLanguage())                    && ("TH".equals(aLocale.getCountry()))) {                cal = new BuddhistCalendar(zone, aLocale);            } else {                cal = new GregorianCalendar(zone, aLocale);            }        } else if (caltype.equals("japanese")) {            cal = new JapaneseImperialCalendar(zone, aLocale);        } else if (caltype.equals("buddhist")) {            cal = new BuddhistCalendar(zone, aLocale);        } else {            // Unsupported calendar type.            // Use Gregorian calendar as a fallback.            cal = new GregorianCalendar(zone, aLocale);        }         return cal;    }          public final Date getTime() {        return new Date(getTimeInMillis());    }

于是我們做一下改進,將對象聲明為private static final,并在靜態(tài)初始化塊中把需要的實例都準備好:

import java.util.Calendar;import java.util.Date;import java.util.TimeZone; class Person {    private final Date birthDate;     public Person(Date birthDate) {        // Defensive copy - see Item 39        this.birthDate = new Date(birthDate.getTime());    }     // Other fields, methods     /**     * The starting and ending dates of the baby boom.     */    private static final Date BOOM_START;    private static final Date BOOM_END;     static {        Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("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;    }}

這樣不僅提高了效率,而且更加明確。

但是,我們還可以再改進一些。如果上面的例子中的isBabyBoomer沒有被調用過,那我們在靜態(tài)初始化塊中創(chuàng)建的實例就白白浪費了(可能例子中的對象太少了,多了就爽了)。對于這個問題,我們可以用延遲初始化(lazily initializing)來解決,也就是在isBabyBoomer被第一次調用時進行初始化。但是作者并不建議這樣做,因為這可能只會讓方法實現(xiàn)變得更復雜,而沒有顯著提高效率。

上面的例子中我們把重用的對象在實例化以后不會再有變化,那么能不能重用可變對象? 比如Map.keySet方法返回的是同一個Set實例,這個Set實例的狀態(tài)依賴于其backing Object,即Map實例。當Map發(fā)生變化時Set也跟著變化就可以了。雖然每次調用時重新創(chuàng)建一個Set實例也是可行的,但實在沒必要。

另外,autoboxing這個特性也為用戶提供了創(chuàng)建不必要的對象的新方法。試試基本類型和封裝類型混用,并讓他們超出封裝類型的緩存范圍。比如這樣做:

public class Sum {    // Hideously slow program! Can you spot the object creation?    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,造成了巨大的浪費。(prefer primitives to boxed primitives,and watch out for unintentional autoboxing.)


上一篇:Effective Java

下一篇:throw和throws

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 南靖县| 铁岭市| 安新县| 泾源县| 兴文县| 哈尔滨市| 靖边县| 孟津县| 武宁县| 花莲县| 塔河县| 黄平县| 乌审旗| 增城市| 六枝特区| 赫章县| 平罗县| 疏勒县| 金秀| 陈巴尔虎旗| 顺义区| 探索| 疏附县| 长葛市| 蚌埠市| 木里| 惠东县| 浮山县| 邵东县| 珠海市| 鄂伦春自治旗| 浑源县| 城步| 吴桥县| 澄迈县| 保德县| 盘山县| 裕民县| 东丽区| 阿拉善盟| 太和县|