前阵子翻了翻《Effective Java》这本书,觉得里面的内容不错,觉得有必要留下些笔记以供以后自己翻看。</span>
本书比较老了,大概总结了jdk1.6及以前版本编程的78条原则,大多数到现在也比较适用。
一、创建和销毁对象
1、考虑用静态工厂方法代替构造器
对于类而言,为了让客户端获得其自身的一个实例,最常用的方法是使用一个公有的构造函数创建一个对象。如下列构造函数:
new BigInteger(int, int, Random);
该构造函数是用于创建一个随机素数,但显然这个构造器并不能很好的表达这个含义,所以我们最好用下面的方法。
BigInteger.probablePrime(int,Ramdom)
在jdk1.4时已经采用了该方法。
这也是静态方法对于构造函数的第一个优势:静态方法有名称,更方便用户阅读。
让我们再看一下另一个j静态工厂方法例子:
Boolean.valueOf(boolean);
Integer.valueOf(int);
该方法可以有效的避免实例重复创建,可以更好的重用实例。
这也是静态方法对于构造函数的第二个优势:不必在每次调用它们的时候都创建一个新的对象。
java1.5中引入了EnumSet,其中只定义了静态方法,是用于操作枚举。EnumSet很多方法都会调用以下的方法:
/**
* Creates an empty enum set with the specified element type.
*
* @param <E> The class of the elements in the set
* @param elementType the class object of the element type for this enum
* set
* @return An empty enum set of the specified type.
* @throws NullPointerException if <tt>elementType</tt> is null
*/
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
Enum<?>[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
}
由该方法可以看出,当枚举数量大于64时会返回JumboEnumSet实现,反之是RegularEnumSet。
这是静态方法对于构造函数的第三个优势:可以返回原返回类型的任何子类型的对象。
在使用泛型时,经常会出现以下:
Map<String,List<String>> map=new HashMap<String,List<String>>();
但如果使用静态方法的话,代码可以更简洁。
假如HashMap中定义了以下方法:
public static <K,V> HashMap<K,V> newInstance(){
return new HashMap<K,V>();
}
那么就可以将new改成如下的方法:
Map<String,List<String>> map=HashMap.newInstance();
这是静态方法对于构造函数的第四个优势:使用泛型创建实例时使用静态共产使代码更简洁。
Map<String,List<String>> map=new HashMap<>();
静态工厂方法的缺点:
1、如果类中没有提供public或protected构造方法,就不能被子类化,但现在一般提倡组合而不是继承,所以并不是问题。
2、和其他静态方法没有任何区别,一般不会在API文档中被标识出来,最好在类的java doc中有明确阐述类实例时需要调用哪个静态方法。
2、遇到多个构造器参数时要考虑使用构建器
静态工厂和构造函数有个共同的局限性,那就是都不能很好的扩展参数。如下代码:
构造函数模式:
public class NutritionFact {
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 NutritionFact(final int servingSize, final int servings, final int calories, final int fat, final int sodium,final int carbohydrate) {
<span style="white-space:pre"> </span>super();
<span style="white-space:pre"> </span>this.servingSize = servingSize;
<span style="white-space:pre"> </span>this.servings = servings;
<span style="white-space:pre"> </span>this.calories = calories;
<span style="white-space:pre"> </span>this.fat = fat;
<span style="white-space:pre"> </span>this.sodium = sodium;
<span style="white-space:pre"> </span>this.carbohydrate = carbohydrate;
}
public NutritionFact(final int servingSize, final int servings) {
<span style="white-space:pre"> </span>this(servingSize, servings, 0, 0, 0, 0);
}
public NutritionFact(final int servingSize, final int servings, final int calories) {
<span style="white-space:pre"> </span>this(servingSize, servings, calories, 0, 0, 0);
}
public NutritionFact(final int servingSize, final int servings, final int calories, final int fat) {
<span style="white-space:pre"> </span>this(servingSize, servings, calories, fat, 0, 0);
}
public NutritionFact(final int servingSize, final int servings, final int calories, final int fat,final int sodium) {
<span style="white-space:pre"> </span>this(servingSize, servings, calories, fat, sodium, 0);
}
}
javabean模式:
public class NutritionFact {
private int servingSize = -1;
private int servings = -1;
private int calories;
private int fat;
private int sodium;
private int carbohyd