EffectiveJava阅读笔记 第2章

创建和销毁对象

第1条 用静态方法代替构造器

获取类的对象,通常有两种方法,一种是创建一个公有的构造器,一种是静态工厂。
如下:

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

静态工厂相比构造器有如下优点:

有名称
静态工厂方法可自己命名,能够更为清楚的描述该方法作用,而构造器只能跟类名相同。而且很多时候需要传入不同的参数,这样就需要多个不同的构造器,就更难区分,而静态工厂方法则能够根据参数指定描述的名称。

不必每次调用都创建一个新的对象
对于final修饰的不可变类,实际没有必要重复创建,只需创建一次并缓存起来重复使用即可。而且可以确保不可变类不会存在两个相同实例

可返回原类型的任意子类型对象
适用于基于接口的框架,例如接口Type的静态工厂方法会被放在Types的不可实例化类中,如通用接口Collection和Collections。
同样也方便服务注册api的实现,以及多种服务的实现。

创建参数化类型实例代码更加简洁
相比构造器一个参数不同就要写不同的构造方法,静态工厂方法通过类型推导就更为简洁。


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

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

静态工厂相比构造器有如下缺点:

类如果没有公有或受保护的构造器,则无法子类化
与其他静态方法没有区别

第2条 多个构造器参数考虑用构建器

静态工厂和构造器都不能很好的扩展到大量可选参数。
如果有很多个参数,那么就需要写大量的构造器方法,如果让构造器方法接收多个参数,则会造成有时必须填写不必要的参数,赋值为0或者空。
当然也可以选择使用JavaBean的方式,创建一个类接收这些参数,将参数都作为类的属性,但这样就无法做到不可变,又需要做额外的工作保证线程安全。
第三种选择就是使用构建器,即Builder模式。
示例:

public class NutritionFacts {
    private final int servingSize; // (mL) required 
    private final int servings;    // (per container) required
    private final int calories;    // (per serving) optional    
    private final int fat;         // (g/serving) optional
    private final int sodium;      // (mg/serving) optional
    private final int carbohydrate; // (g/serving) optional
    public NutritionFacts(int servingSize, int servings) { 
        this(servingSize, servings, 0);
    }
    public NutritionFacts(int servingSize, int servings, int calories) {
        this(servingSize, servings, calories, 0); 
    }
    public NutritionFacts(int servingSize, int servings, int calories, int fat) {
        this(servingSize, servings, calories, fat, 0); 
    }
    public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium) {
        this(servingSize, servings, calories, fat, sodium, 0); 
    }
    public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium, 
        int carbohydrate) {
        this.servingSize = servingSize; this.servings = servings;
        this.calories = calories
        this.fat = fat
        this.sodium = sodium
        this.carbohydrate = carbohydrate;
    } 
}

这里也可以使用setter方法设置参数,还能在方法里面检验传入的参数是否有效,并抛出异常。
相比与构造器,使用Builder可以灵活的控制参数。
Builder缺点是必须给类写个构建器,有时没有必要,而且还会增大内存开销,影响性能。

最好一开始就决定是否使用构造器,避免以后因参数过多而需要添加构建器时需改动过多的代码。Builder模式适用于,构造器和静态工厂中有很多参数的场景。

发布了79 篇原创文章 · 获赞 3 · 访问量 5250

猜你喜欢

转载自blog.csdn.net/SW_LCC/article/details/103115751