第四条:通过私有构造器强化不可实例化的能力
java.lang.Math,java.util.Arrays这种工具类无需实例化,因为毫无意义,但是在缺少显式构造器的情况下,编译器会自动构建一个公有的无参构造器,这些工具类可能会在无意识的情况下被实例化,或是被继承,并且,企图将这种类做成抽象类限制实例化是行不通的,因为继承抽象类的子类仍然可被实例化,同时会造成误解。解决办法是让这种工具类包含一个私有的构造器,这样可以保证类不被实例化,同时也不可被继承,因为子类无法调用父类的构造器。
第五条:优先考虑依赖注入来引用资源
许多类会依赖一个或多个底层资源,同时要求底层资源是可以修改的(同一个类的多个实例),满足该需求的最简单的模式是,当创建一个新的实例时,就将资源传入类的构造器中(这就是依赖注入),实现如下。
public class DependencyDemo { public static void main(String[] args) { new People(new Apple()); } } class People { public People(Fruit fruit) { fruit.eat(); } } interface Fruit { void eat(); } class Apple implements Fruit { @Override public void eat() { System.out.println("eat apple"); } } class Banana implements Fruit { @Override public void eat() { System.out.println("eat banana"); } }
不要使用单例或工具类实现一个需要依赖底层资源的类,因为资源的行为会影响类的行为,也不要直接创建资源,应使用依赖注入的方式。依赖注入的资源对象具有不可变性,因此多个客户端可以共享依赖对象,依赖注入的这种模式同样适用于静态工厂、构造器、构建器。依赖注入的另一个变体是将资源工厂传给构造器,客户端可创建任意子类型。
第六条:避免创建不必要的对象
将String s = new String("abc"),修改为String s = "abc";前者多次执行每次都构建一个新的对象,后者多次执行每次都使用缓冲区同一字符常量。
对于同时提供了构造器和静态工厂方法的不可变类,应优先使用静态工厂方法,避免创建不必要的对象。
有些对象创建成本昂贵,应缓存下来重复使用,如使用String.matches方法匹配正则表达式,其在内部为正则表达式创建Pattern实例,并且使用一次后就会被回收,为了提升性能,将正则表达式编译成一个Pattern实例,同时在创建类的实例时初始化,缓存起来,达到重用目的。
自动装箱也会创建多余对象,在仅做计算无需判空的操作下,应优先使用基本类型而非包装类。
同时,并非任何情况下都要避免创建对象,一些小对象的创建和回收是非常廉价的,无需维护在对象池中,对象池中维护的对象应是非常重量级的,典型如数据库连接池。