第二章 创建和销毁对象(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条:避免使用终结方法--这个基本没用过