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
- **总结:**
+ 方法名尽量采用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模式那么好的可读性:
####
####
####
####
####
####