读书笔记《Effective Java》

来源:互联网 发布:知乐作品集百度网盘 编辑:程序博客网 时间:2024/05/05 15:11

第二章 创建和销毁对象(1-7条)
第二条:遇到多个构造器参数时要考虑用构建器
适用情况:当一个类中有必要参数和大量可选参数的时候
解决方法:
1.重叠的构造器模式
缺点:当有许多参数的时候,客户端代码会很难编写,而且仍然较难以阅读
2.使用javabean
缺点:javabean模式阻止把类做成不可变的可能
3.推荐方法,使用builder模式
package test;

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;
  
  //optinal parameters
  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){
   this.calories = val;
   return this;
  }
  public Builder fat(int val){
   this.fat = val;
   return this;
  }
  public Builder carbohydrate(int val){
   this.carbohydrate = val;
   return this;
  }
  public Builder sodium(int val){
   this.sodium = val;
   return this;
  }
  public NutritionFacts build(){
   return new NutritionFacts(this);
  }
 }
 
 private NutritionFacts(Builder builder){
  this.servingSize = builder.servingSize;
  this.servings = builder.servings;
  this.calories = builder.calories;
  this.fat = builder.fat;
  this.sodium = builder.sodium;
  this.carbohydrate = builder.carbohydrate;
 }
}

好处:客户端代码容易编写,易于阅读

第3条:用私有构造器或者枚举类型强化Singleton属性
一般的单例实现方法:
public class Elvis{
 public static final Elvis INSTANCE = new Elvis();
 private Elvis(){...}

 public void leaveTheBuilding(){...}
}

单元素的枚举类型已经成为实现Singleton的最佳方法,代码如下:
public enum Elvis{
 INSTANCE;
 public void leaveTheBuilding(){...}
}

第4条:通过私有构造器强化不可实例化的能力
有些不希望用户实例化的类,可以手动添加一个私有的构造器以阻止被自动添加无参构造器

第5条:避免创建不必要的对象
除了重用不可变的对象外,也可以重用那些已知不会被修改的可变对象。
要优先使用基本类型而不是装箱基本类型,要当心无意识的自动装箱。
例子:
public class Person {
 private final Date birthdayDate;
 public Person(Date birthday){
  this.birthdayDate = birthday;
 }
 public boolean isBabyBoomer(){
  Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
  gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
  Date boomStart = gmtCal.getTime();
  gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
  Date boomEnd = gmtCal.getTime();
  return birthdayDate.compareTo(boomStart) >= 0 && birthdayDate.compareTo(boomEnd) < 0;
 }
 public static void main(String[] args) {
  long start = System.currentTimeMillis();
  for(int i = 0; i < 1000000; i++){
   Person p = new Person(new Date());
   p.isBabyBoomer();
  }
  long end = System.currentTimeMillis();
  System.out.println("time :" + (end  - start));
 }
}
该程序执行时间2秒多
public class Person2 {
 private final Date birthDate;
 private static final Date BOOM_START;
 private static final Date BOOM_END;
 
 public Person2(Date d){
  this.birthDate = d;
 }
 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;
 }
 
 public static void main(String[] args) {
  long start = System.currentTimeMillis();
  for(int i = 0; i < 1000000; i++){
   Person2 p2 = new Person2(new Date());
   p2.isBabyBoomer();
  }
  long end = System.currentTimeMillis();
  System.out.println("time :" + (end  - start));
 }
}
该程序自行时间70多毫秒

提示:要有限使用基本类型而不是装箱基本类型,要当心无意识的自动装箱

第6条:消除过期的对象引用--几个有意义的忠告
请注意无意识的对象保存
消除过期引用最好的方式是让包含该引用的变量结束其生命周期。如果你是在最紧凑的作用域范围内定义每一个变量(见45条),这种情形就会自然而然的发生。
一般而言,只要是自己管理内存,程序员就应该警惕内存泄露问题。一旦元素被释放掉,则该元素中包含的任何对象引用都应该被清空。

第7条:避免使用终结方法--这个基本没用过