Effective-Java——创建和销毁对象

By timebusker on May 8, 2018

Effective-Java——创建和销毁对象

何时以及如何创建对象,何时以及如何避免创建对象,如何确保适时的销毁对象,以及如何管理对象销毁之前必须进行的各种清理工作?

考虑用静态工厂方法代替构造器

换言之,初始化类时,尽量通过类本身提供的静态工厂明确参数和职能的创建实例,避免通过new Object()创建。

  • 好处:
    • 相对于构造器,有明确的方法名称,便于阅读。
    • 可实现单例模式,不必每次都创建对象。
    • 可以返回任何子类型的对象实例,选择对象类时更加灵活。
    • 创建参数化实例时,科学地利用类型推到,可以简化代码。 ```java Map<String,List> m= new HashMap<String, List>();

// ——————————————————

public static <k,v> HashMap<k,v> newInstance(){
return new HashMap<k,v>();
}
Map<String,List> m= HashMap.newInstance()

- **总结:**  
  + 方法名尽量采用valueOf、of、getInstance、newInstance、getType、newType
  + 与构造器方式各有长处,灵活使用

#### 遇到多个构造器参数时要考虑构造器
静态工厂方法和构造器有一个共同的局限:他们不能很好的扩展到大量可选参数。一种思路是重叠构造器(telescoping constructor,多个构造器之前嵌套调用)可以解决,
但当参数过多时,客户端会很难编写。另一种思路是JavaBean模式,通过调用无参构造器来创建对象,然后使用`setter`方法设置属性值。

JavaBean模式存在致命的问题是:线程不安全,导致对象状态不一致
(类不能仅仅通过校验构造器参数的有效性来保证一致性,当多个线程共享一个对象时,简单的setter方法不能保证对象状态一致。)。   

第三种思路是Builder模式,既能保证想重叠构造器一样安全,又能实现JavaBean模式一样的可读性。
```java
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 {
        // 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 carbohydrate = 0;
        private int sodium = 0;

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

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

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

        public Builder carbohydrate(int val) {
            carbohydrate = 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;
    }

    public static void main(String[] args) {
        NutritionFacts cocaCola = new Builder(240, 8).calories(100).sodium(35).carbohydrate(27).build();
    }
}

此时采用Builder方式(尤其是当大多数参数时可选时)替代重叠构造器、JavaBean方式,既能保证重叠构造器那样的安全性,也能保证JavaBeans模式那么好的可读性:

####

####

####

####

####

####