《effective java》之一:创建和销毁对象
public class Services {private Services() {} // Prevents instantiation (Item 4)// Maps service names to servicesprivate static final Map<String, Provider> providers = new ConcurrentHashMap<String, Provider>();public static final String DEFAULT_PROVIDER_NAME = "<def>";// Provider registration APIpublic static void registerDefaultProvider(Provider p) {registerProvider(DEFAULT_PROVIDER_NAME, p);}public static void registerProvider(String name, Provider p) {providers.put(name, p);}// Service access APIpublic static Service newInstance() {return newInstance(DEFAULT_PROVIDER_NAME);}public static Service newInstance(String name) {Provider p = providers.get(name);if (p == null)throw new IllegalArgumentException("No provider registered with name: " + name);return p.newService();}}
?
第2条:遇到多个构造器参数时要考虑用构建器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 parametersprivate final int servingSize;private final int servings;// Optional parameters - initialized to default valuesprivate 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();}}?
第3条:用私有构造器或者枚举类型强化Singleton属性:
?
从Java 1.5发行版开始,实现Singleton的最佳实践方法是,编写一个包含单个元素的枚举类型:
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();}}?
第4条:通过私有构造器强化不可实例化的能力:
?
// Noninstantiable utility classpublic class UtilityClass {// Suppress default constructor for noninstantiabilityprivate UtilityClass() {throw new AssertionError();}}?
第5条:避免创建不必要的对象:
?
除了重用不可变对象外,也可以重用那些已知不会被修改的可变对象。
class Person {private final Date birthDate;public Person(Date birthDate) {// Defensive copy - see Item 39this.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;}}?
?第6条:消除过期的对象引用:
?
内存泄露的一个典型例子:
public class Stack {private Object[] elements;private int size = 0;private static final int DEFAULT_INITIAL_CAPACITY = 16;public Stack() {elements = new Object[DEFAULT_INITIAL_CAPACITY];}public void push(Object e) {ensureCapacity();elements[size++] = e;}public Object pop() {if (size == 0)throw new EmptyStackException();return elements[--size];}/** * Ensure space for at least one more element, roughly doubling the capacity * each time the array needs to grow. */private void ensureCapacity() {if (elements.length == size)elements = Arrays.copyOf(elements, 2 * size + 1);}}?从栈中弹出来的对象不会当做垃圾回收,因为栈内部维护着这些对象的过期引用(obsolete reference),所谓的过期引用,是指永远不会再被解除的引用。本例中,凡是elements数组的活动部分之外的任何引用都是过期的,活动部分是指elements中下标小于size的那些元素。
pop方法的修订版:
public Object pop() { if(size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; // Eliminate obsolete reference return result;}?一般而言,只要类是自己管理内存,程序员就应该警惕内存泄露问题,一旦元素被释放掉,则该元素中包含的任何对象引用都应该被清空。
内存泄露的另一个来源是缓存。
内存泄露的第三个来源是监听器和其他回调。确保回调立即被当做垃圾回收的最佳方法是只保留它们的弱引用 weak reference,例如,只将它们保存成WeakHashMap中的key
?
第7条:避免使用终结方法finalizer:
?
finalizer通常是不可预测的,也是很危险的,一般情况下是不必要的。会导致不稳定,性能降低,不可移植。