Effective Java -- 创建和销毁对象
静态工厂方法代替构造器
- 可以返回原返回类型的任何子类型对象;
- 不必每次调用他们的时候都去创建一个对象;
- 有名称;
- 创建参数化类型实例的时候,使得代码更加简洁。
静态工厂方法的缺点:
- 如果不含公有的或者受保护的构造器,就 不能被子类实例化;
- 与其他的静态方法实际上没有任何区别。
遇到多个构造器参数的时候考虑使用builder模式
- 利用javaBean的set方法来设置;
- 最佳方法:使用Builder模式来构造多参数的类对象。
builder模式优点:
- 灵活,可以利用单个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; 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 NutritionFacts.Builder(240, 8) .calories(100).sodium(35).carbohydrate(27).build(); } }
用私有构造器或者枚举类型强化单利
使用枚举:
public enum Elvis { INSTANCE; public void leaveTheBuilding() { System.out.println("Whoa baby, I'm outta here!"); } // This code would normally appear outside the class! public static void main(String[] args) { Elvis elvis = Elvis.INSTANCE; elvis.leaveTheBuilding(); } }
通过构建私有构造器强化不可实例化的能力
public class UtilityClass { // Suppress default constructor for noninstantiability private UtilityClass() { throw new AssertionError(); } }
子类继承报错,其他类调用也会出错。
避免创建不必要的对象
能重用对象绝不创建新对象。
优先使用基本类型而不是装箱基本类型,要当心无意义的自动装箱。
class Person { private final Date birthDate; public Person(Date birthDate) { // Defensive copy - see Item 39 this.birthDate = new Date(birthDate.getTime()); } // Other fields, methods /** * The starting and ending dates of the baby boom. */ private static final Date BOOM_START; private static final Date BOOM_END; static { Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0); BOOM_START = gmtCal.getTime(); gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0); BOOM_END = gmtCal.getTime(); } public boolean isBabyBoomer() { return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo(BOOM_END) < 0; } }
消除过期对象的引用
- 一旦引用过期,就需要对引用进行清空。
- 使用weakHashMap代表缓存,当缓存过期,自动删除。
- 确保回调立即被当做垃圾回收的最佳方法是保持它们的弱引用。
避免使用终结方法
终结方法不可预测,很危险,不必要。
java语言不保证终结方法及时执行,不保证会被执行。能够保证终结方法被执行的方法是System.runFinalizersOnExit(),Runtime.runFinalizersOnExit()。
使用终结方法存在严重的性能问题。
显示终止方法例子:IO流中的close方法。Timer的cannel方法。
如果使用终结方法,也要记住调用super.finalize。