《effective java》之一:创建和销毁对象 博客分类: Java effectivejava
程序员文章站
2024-02-15 08:55:22
...
第1条:考虑用静态工厂方法代替构造器:
public class Services { private Services() { } // Prevents instantiation (Item 4) // Maps service names to services private static final Map<String, Provider> providers = new ConcurrentHashMap<String, Provider>(); public static final String DEFAULT_PROVIDER_NAME = "<def>"; // Provider registration API public static void registerDefaultProvider(Provider p) { registerProvider(DEFAULT_PROVIDER_NAME, p); } public static void registerProvider(String name, Provider p) { providers.put(name, p); } // Service access API public 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 parameters private final int servingSize; private final int servings; // Optional parameters - initialized to default values 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) { 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 class public class UtilityClass { // Suppress default constructor for noninstantiability private UtilityClass() { throw new AssertionError(); } }
第5条:避免创建不必要的对象:
除了重用不可变对象外,也可以重用那些已知不会被修改的可变对象。
class Person { private final Date birthDate; public Person(Date birthDate) { // Defensive copy - see Item 39 this.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通常是不可预测的,也是很危险的,一般情况下是不必要的。会导致不稳定,性能降低,不可移植。
本人博客已搬家,新地址为:http://yidao620c.github.io/
推荐阅读
-
Effective Java读书笔记、感悟——2.1对所有对象都通用的方法之equals 博客分类: Java_SE effectivejava对象通用方法equals
-
《effective java》之一:创建和销毁对象 博客分类: Java effectivejava
-
Effective Java读书笔记、感悟——1.创建和销毁对象 博客分类: Java_SE effectivejava对象创建对象销毁
-
《effective java》之二:对于所有对象都通用的方法 博客分类: Java effectivejava
-
Effective Java读书笔试之创建和销毁对象 博客分类: effective java effectivejava