Effective Java
第1条:考虑用静态工厂方法代替构造器
【尚未彻底读懂笔者的意图】
第2条:遇到多个构造器参数时要考虑用构造器
1.使用重叠构造器:缺点是写太多
2.使用JavaBean模式:缺点是不一致
3.使用Builder模式:先创造构造器,太冗长
Builder模式:
1 public class NutritionFacts{ 2 private final int servingSize; 3 private final int servings; 4 private final int calories; 5 private final int fat; 6 private final int sodium; 7 private final int carbohydrate; 8 9 public static class Builder{ 10 private final int servingSize; 11 private final int servings; 12 13 private int calories=0; 14 private int fat=0; 15 private int sodium=0; 16 private int carbohydrate=0; 17 18 public Builder(int servingSize,int servings){ 19 this.servingSize=servingSize; 20 this.servings=servings; 21 } 22 23 public Builder calories(int value){ 24 calories=value; 25 return this; 26 } 27 28 public Builder fat(int value){ 29 fat=value; 30 return this; 31 } 32 33 public Builder sodium(int value){ 34 sodium=value; 35 return this; 36 } 37 38 public Builder carbohydrate(int value){ 39 carbohydrate=value; 40 return this; 41 } 42 43 public NutritionFacts build(){ 44 return new NutritionFacts(this); 45 } 46 47 } 48 49 private NutritionFacts(Builder builder){ 50 servingSize=builder.servingSize; 51 servings=builder.servings; 52 calories=builder.calories; 53 fat=builder.fat; 54 sodium=builder.sodium; 55 carbohydrate=builder.carbohydrate; 56 } 57 58 public static void main(String[] args){ 59 NutritionFacts cocaCola=new NutritionFacts.Builder(240,8).calories(100).sodium(35).carbohydrate(27).build(); 60 System.out.println("cocaCola nutritionfacts build success."); 61 } 62 }
第3条:用私有构造器或者枚举类型强化Singleton属性
1.公有静态成员是个final域:缺点是享有特权的客户端可以通过AccessibleObject.setAccessible方法,通过反射机制调用私有构造器
1 public class Elvis{ 2 public static final Elvis INSTANCE=new Elvis(); 3 private Elvis(){} 4 }
2.公有的成员是个静态工厂方法:
1 public class Elvis{ 2 private static final Elvis INSTANCE=new Elvis(); 3 private Elvis(){} 4 public static Elvis getInstance(){ 5 return INSTANCE; 6 } 7 }
同时,在利用静态工厂方法实现Singleton类变成可序列化的,仅仅在声明上加上implements Serializable是不够的。为了维护并且保证Singleton,必须声明所有实例都是瞬时的,并且提供一个readResolve方法。否则,每次反序列化一个序列化的实例时,都会创建一个新的实例。【尚未清楚,为啥加了readResolve方法就能防止】
1 public class Elvis{ 2 private static final Elvis INSTANCE=new Elvis(); 3 private Elvis(){} 4 5 public static Elvis getInstance(){ 6 return INSTANCE; 7 } 8 9 private Object readResolve(){ 10 return INSTANCE; 11 } 12 }
3.编写一个包含单个元素的枚举类型:
1 public enum Elvis{ 2 INSTANCE; 3 4 public void leaveTheBuilding(){} 5 }
单元素的枚举类型已经成为了实现Singleton的最佳方法。
第4条:通过私有构造器强化不可实例化的能力:
1 public class UtilityClass{ 2 private UtilityClass(){ 3 throw new AssertionError(); 4 } 5 }
第5条:避免创建不必要的对象
1.通常使用静态工厂方法而不是构造器,以避免创建不必要的对象。
1 class Person{ 2 private final Date birthDate; 3 private static final Date BOOM_START; 4 private static final Date BOOM_END; 5 6 static{ 7 Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); 8 gmtCal.set(1946,Calendar.JANUARY,1,0,0,0); 9 BOOM_START=gmtCal.getTime(); 10 gmtCal.set(1965,Calendar.JANURAY,1,0,0,0); 11 BOOM_END=gmtCal.getTime(); 12 } 13 14 public boolean isBabyBoomer(){ 15 return birthDate.compareTo(BOOM_START)>=0&&bithDate.compareTo(BOOM_END)<0; 16 } 17 }
2.如果可以的话,使用延迟初始化(lazily initializing)。但是不太建议这么做,因为会使方法更加复杂。
3.考虑使用适配器(adapter)的情况:将功能委托给一个后备对象,从而为后备对象提供一个可以替代的接口。
4.要优先使用基本类型,而不是装箱基本类型,要担心无意识的自动装箱。
1 public class Test { 2 public static void main(String[] args) { 3 Long sum = 0L; 4 /* long sum=0L; */ 5 for (long i = 0; i < Integer.MAX_VALUE; i++) { 6 sum += i; 7 } 8 System.out.println(sum); 9 } 10 }
5.小对象的创建和回收动作是非常廉价的
6.通过维护自己的对象池来避免创建对象并不是一种好的做法,除非对象池中的对象是非常重量级的。
第6条:消除过期的对象引用