《Effective Java第二版》閱讀小記

  • 方法的簽名(signature)由它的名稱和所有參數(shù)類型組成;簽名不包括它的返回類型。
  • 考慮用靜態(tài)工廠方法代替構(gòu)造器
    比如EnumSet的靜態(tài)工廠方法,如果它的元素有64個(gè)或者更少,靜態(tài)工廠方法就會(huì)返回一個(gè)RegalarEnumSet實(shí)例,用單個(gè)long進(jìn)行支持;如果有65個(gè)元素或以上,工廠返回JumboEnumSet,用long數(shù)組進(jìn)行支持。
    服務(wù)提供者框架:①服務(wù)接口;②服務(wù)提供者注冊(cè)API;③服務(wù)訪問(wèn)API;④服務(wù)提供者接口(可選)
  • 遇到多個(gè)構(gòu)造器參數(shù)時(shí)要考慮用構(gòu)建器(Builder模式)
/**
 * @Description:遇到多個(gè)構(gòu)造器參數(shù)時(shí)要考慮用構(gòu)建器(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;

    // 靜態(tài)內(nèi)部類
    public static class Builder {
        // 必須的參數(shù)使用final修飾,切放在構(gòu)造器中,為了保證一定要賦值
        // 可選的參數(shù)使用默認(rèn)賦值,使用方法賦值,體現(xiàn)可選性


        // required parameters
        private final int servingSize;
        private final int servings;

        // optional parameters - initialized to default values
        private int calories = 0;
        private int fat = 0;
        private int sodium = 0;
        private int carbohydrate = 0;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }

        public Builder calories(int val) {
            this.calories = val;
            return this;
        }

        public Builder fat(int val) {
            this.fat = val;
            return this;
        }

        public Builder sodium(int val) {
            this.sodium = val;
            return this;
        }

        public Builder carbohydrate(int val) {
            this.carbohydrate = val;
            return this;
        }

        public NutritionFacts build() {
            return new NutritionFacts(this);
        }
    }

    // 構(gòu)造器私有化
    private NutritionFacts(Builder build) {
        this.servingSize = build.servingSize;
        this.servings = build.servings;
        this.calories = build.calories;
        this.fat = build.fat;
        this.sodium = build.sodium;
        this.carbohydrate = build.carbohydrate;
    }

    @Override
    public String toString() {
        return "NutritionFacts{" +
            "servingSize=" + servingSize +
            ", servings=" + servings +
            ", calories=" + calories +
            ", fat=" + fat +
            ", sodium=" + sodium +
            ", carbohydrate=" + carbohydrate +
            '}';
    }

    public static void main(String... args) {
        NutritionFacts nf = new Builder(1, 0).calories(100).fat(50).sodium(22).carbohydrate(250).build();
        System.out.println(nf);
    }
}

  • 用私有構(gòu)造器或者枚舉類型強(qiáng)化Singleton屬性
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @Description:?jiǎn)卫男蛄谢? * @Author: baitengpeng
 * @Date: 2018/5/25 下午2:05
 */
public class SingletonSerializable implements Serializable {
    private transient String name = "the singleton object";
    private transient int mumber = 13;

    private static SingletonSerializable singleton = null;

    static{
        singleton = new SingletonSerializable();
    }

    private SingletonSerializable(){
        // 防止通過(guò)反射破解單例
        if(null != singleton){
            throw new IllegalStateException("illegal operate");
        }
    }

    // 防止通過(guò)序列化反序列化破解單例
    private Object readResolve(){
        return singleton;
    }

    public static SingletonSerializable getInstance(){
        return singleton;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getMumber() {
        return mumber;
    }

    public void setMumber(int mumber) {
        this.mumber = mumber;
    }

    @Override
    public String toString() {
        return "SingletonSerializable{" +
            "name='" + name + '\'' +
            ", mumber=" + mumber +
            '}';
    }

    public static void main(String...args)
        throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
        // 寫對(duì)象
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(SingletonSerializable.getInstance());

        // 讀對(duì)象
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
        SingletonSerializable singletonSerializable = (SingletonSerializable) ois.readObject();

        // 比較讀的對(duì)象和原先的對(duì)象是否相等
        System.out.println(SingletonSerializable.getInstance() == singletonSerializable);
        System.out.println(SingletonSerializable.getInstance());
        System.out.println(singletonSerializable);

        Class<SingletonSerializable> clazz = SingletonSerializable.class;
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        for(Constructor c : constructors){
            c.setAccessible(true);
            System.out.println(SingletonSerializable.getInstance() == c.newInstance());
        }

//        SingletonSerializable objectFromReflection = clazz.newInstance();
//        System.out.println(SingletonSerializable.getInstance() == objectFromReflection);
//        System.out.println(objectFromReflection);
    }
}

  • 通過(guò)私有構(gòu)造器強(qiáng)化不可實(shí)例化的能力
/**
 * @Description:工具類,只包含靜態(tài)方法和靜態(tài)成員變量,這種類不希望被實(shí)例化
 * @Author: baitengpeng
 * @Date: 2018/5/25 下午3:11
 */
public class UtilityClass {
    // 將它的構(gòu)造器聲明為private,且為了防止反射,在構(gòu)造器中拋出異常
    private UtilityClass(){
        throw new AssertionError();
    }
    // 靜態(tài)方法和靜態(tài)成員變量
    // ...
}
  • 避免創(chuàng)建不必要的對(duì)象
    當(dāng)你應(yīng)該重用現(xiàn)有對(duì)象的時(shí)候,請(qǐng)不要?jiǎng)?chuàng)建新的對(duì)象。

  • 消除過(guò)期的對(duì)象引用
    對(duì)于不再使用的對(duì)象引用,將其賦值為null。
    巧妙使用WeakHashMap

  • 避免使用終結(jié)方法
    從一個(gè)對(duì)象變得不可到達(dá)開始,到它的終結(jié)方法被執(zhí)行,所花費(fèi)的這段時(shí)間是任意長(zhǎng)的。終結(jié)方法不能保證會(huì)被及時(shí)地執(zhí)行。
    如果未被捕獲的異常在終結(jié)過(guò)程中被拋出來(lái),那么方法會(huì)終止,而且什么都不會(huì)打印出來(lái)。
    如果需要終止,可以為對(duì)象提供一個(gè)顯式的終止方法。多和try{}catch(){}finally{}結(jié)合起來(lái)使用。比如InputStream的close方法。

  • 覆蓋equals時(shí)請(qǐng)遵守通用約定
    如果類具有自己特有的“邏輯相等”概念,則需要覆蓋equals方法。
    比較float和double類型的值使用Float.compareDouble.compare
    為了提高equals方法的性能,應(yīng)該先比較最有可能不一致的域,或者是開銷最低的域。
    equals滿足:①自反性②對(duì)稱性③傳遞性④非空性

  • 覆蓋equals時(shí)總要覆蓋hashCode
    equals相等,hashCode必相等。
    equals不等,hashCode有可能相等。
    equals不等的對(duì)象,hashCode相等,如果是在HashMap中,就是放在一個(gè)桶里,兩個(gè)對(duì)象鏈接起來(lái),所以hashCode不相等可以提高性能。

    重寫hashCode方法

數(shù)字31的一個(gè)優(yōu)良的性質(zhì)是:乘法可以被位移和減法替代: 
31 * i == (i << 5) - i
  • 始終要覆蓋toString
    可以通過(guò)toString獲取到關(guān)鍵性的信息,而且可讀性好。

  • 謹(jǐn)慎地覆蓋clone

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 31,765評(píng)論 18 399
  • 目錄 第二章 創(chuàng)建和銷毀對(duì)象 1 考慮用靜態(tài)工廠方法替代構(gòu)造器 對(duì)于代碼來(lái)說(shuō), 清晰和簡(jiǎn)潔是最重要的. 代碼應(yīng)該被...
    高廣超閱讀 1,471評(píng)論 0 12
  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂(lè)視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,366評(píng)論 11 349
  • 《詩(shī)經(jīng)·豳風(fēng)·東山》 我徂東山,慆慆不歸。我來(lái)自東,零雨其濛。我東曰歸,我心西悲。制彼裳衣,勿士行枚。蜎蜎者蠋,烝...
    七徽閱讀 2,395評(píng)論 31 55
  • 未經(jīng)審視的人生不值得過(guò),未經(jīng)審視的物品也不應(yīng)當(dāng)收納。 整理是生活中常做的一件事,但很多人都把整理看做一個(gè)繁瑣無(wú)趣的...
    欣興媽媽閱讀 2,088評(píng)論 0 1