目录
创建和销毁对象
1.静态工厂方法代替构造器
在设计类对外提供的实例化方式的时候, 除了定义公有构造方法(public constructor),还可以考虑提供一个公有的静态工厂方法(static factory method).
使用静态工厂方法的好处:
- 使用静态工厂方法可以提高代码的可读性,通过方法的命名可以描述出类的构造行为.使用你设计的类的人可以通过方法名称很快地知道这个方法是实例化的什么对象.
例如:
public class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
// 通过方法名称可以很快地知道是要创建一个怎样的对象实例
public static Animal createCat() {
return new Animal("Cat");
}
public static Animal createDog() {
return new Animal("Dog");
}
}
- 可以控制类实例化时,不必每次都创建出新的实例.例如,单例模式(Singleton)
- 使用构造器创建实例只能返回自身,而静态工厂方法可以返回子类型的实例,使实例创建更灵活.
- 使用静态工厂方法创建一些泛型类的时候,可以是代码更加简洁.
例如:
// JDK1.7之前的版本,创建List集合使用构造器, ArrayList后面的泛型相关信息不能省略不写
List<Map<String, String>> ls = new ArrayList<Map<String, String>>();
// 使用静态工厂方法,就可以简化代码量, Guava中Lists的静态工厂方法
List<Map<String, String>> list = Lists.newArrayList();
2.当设计的类有许多字段的时候,考虑使用builder
这是Builder Pattern的一种形式
public class NutritionInfo {
// 必须字段
// 净含量 mL
private final int netWeight;
// 可选字段
// 卡路里 g
private final int calories;
// 脂肪 g
private final int fat;
// 钠 mg
private final int sodium;
// 糖类 g
private final int carbohydrate;
public static class Builder {
private final int netWeight;
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;
public Builder(int netWeight) {
this.netWeight = netWeight;
}
public Builder calories(int val) {
calories = val;
return this;
}
public Builder fat(int val) {
fat = val;
return this;
}
public Builder sodium(int val) {
sodium = val;
return this;
}
public Builder carbohydrate(int val) {
carbohydrate = val;
return this;
}
public NutritionInfo build() {
return new NutritionInfo(this);
}
}
private NutritionInfo(Builder builder) {
netWeight = builder.netWeight;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
}
客户端调用示例:
// 这样就能控制netWeight字段必输,而其他营养成分字段可以根据实际的情况进行设置
NutritionInfo sodaWater = new NutritionInfo.Builder(330).sodium(12).build();
NutritionInfo cocaCola = new NutritionInfo.Builder(330).sodium(35).carbohydrate(27).calories(100).build();
3.利用private constructor和enum type强化单例类的属性
利用private constructor或者声明成枚举类(JDK1.5开始)将实例化行为放到类的内部,保证外部无法破坏单例的唯一性.
4.利用private constructor强化类不可实例化
使用场景:工具类一般都不需要实例化, 在自己编写一个工具类的时候声明private constructor.
public class StringUtils {
private StringUtils() {}
// ...
}
5.避免创建不必要的对象
一般情况,代码中最好能复用一个相同的的实例,而不是每次需要的时候再实例化出一个功能相同的对象.
一个对象如果是不可变的(immutable),那么就可以一直被复用.
// 每次调用都会创建出一个新的实例, 而且传给String构造器的参数本身也是一个String实例
String s = new String("abc");
// 改进后的版本
String s1 = "abc";
6.消除过期对象引用
public class Stack {
private Object[] elemenets;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elemenets = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
elemenets[size++] = e;
}
public Object pop() {
if (size == 0) {
throw new EmptyStackException();
}
return elemenets[--size];
}
private void ensureCapacity() {
if (elemenets.length == size) {
elemenets = Arrays.copyOf(elemenets, 2 * size + 1);
}
}
}
栈先增长再收缩会导致内存泄漏, 大于size的部分的元素并没有被回收而是一直保持在数组中.
7.避免使用finalize方法
Java中已经废弃Object中的finalize方法的使用.
该方法不稳定,可能影响性能.