读书人

《effective java》之一:创造和销毁对

发布时间: 2013-03-29 14:24:52 作者: rapoo

《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通常是不可预测的,也是很危险的,一般情况下是不必要的。会导致不稳定,性能降低,不可移植。

读书人网 >编程

热点推荐